import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.universe.SimpleUniverse;
import com.sun.j3d.utils.applet.MainFrame;
import java.util.*;

public class Prismatic extends Applet implements ActionListener, AdjustmentListener {

   String host;                    // Host from which this applet came from
   int width, height;              // Size of the graphics window in pixels
   Canvas3D canvas3D;              // 3D rendering canvas
   Panel b_container;              // Container to hold the buttons
   Panel c_container;              // Container to hold the canvas
   Panel l_container;              // Container to hold the labels
   Panel instruct_panel;           // Panel to hold Introduction
   Button instruct_button;         // Introduction button
   Button update_button;           // Update button
   TextArea instruct_text;         // TextArea object that holds Introduction
   Button instruct_return_button;  // Return button for instruction panel
   InputStream inStream;           // Input stream for reading Introduction
   static boolean appletFlag = true;      // Applet flag
   byte text[];                    // Temporary storage area for reading introduction file
   String textString;              // Storage area for introduction

    private SimpleUniverse universe = null;
    int zoom;
    TextField nNum, hNum, vNum, HNum, nInput;
    BranchGroup scene3D;
    Scrollbar HSlider;
    int n, h, v;
    double H;

   /**
    * Initialization
    */
   public void init() {

      // Set the graphics window size.
      width  = 350;
      height = 350;          
      zoom = 50;
      n = 5;
      h = 1;
      v = 1;
      H = 1;

      // Create the "base" color for the AWT components.
      setBackground(new Color(200, 200, 200));

      // Read the introduction file.
       if (appletFlag) {

         // Get the host from which this applet came.
         host = getCodeBase().getHost();

         try {
            inStream = new BufferedInputStream
               (new URL(getCodeBase(), "introduction.txt").openStream(), 8192);
            text = new byte[5000];
            int character = inStream.read();
            int count = 0;
            while (character != -1) {
               text[count++] = (byte) character;
               character = inStream.read();
            }
            textString = new String(text);
            inStream.close();
         }
         catch(Exception e) {
            System.out.println("Error: " + e.toString());
         }
      }
      else {

         try {
            inStream = new BufferedInputStream
               (new FileInputStream("introduction.txt"));
            text = new byte[5000];
            int character = inStream.read();
            int count = 0;
            while (character != -1) {
               text[count++] = (byte) character;
               character = inStream.read();
            }
            textString = new String(text);
            inStream.close();
         }
         catch(Exception e) {
            System.out.println("Error: " + e.toString());
         }
      }

      // Create a 3D graphics canvas.
      canvas3D = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
      canvas3D.setSize(width, height);
      canvas3D.setLocation(5, 5);

      // Create the branch group
      createScene3D();

      // Create a universe with the Java3D universe utility.
      universe = new SimpleUniverse(canvas3D);
      universe.addBranchGraph(scene3D);
  
      // Use parallel projection.
      View view = universe.getViewer().getView();
      view.setProjectionPolicy(View.PARALLEL_PROJECTION);

      // Set the universe Transform3D object.
      TransformGroup tg = 
         universe.getViewingPlatform().getViewPlatformTransform();
      Transform3D transform = new Transform3D();
      transform.set(65.f, new Vector3f(0.0f, 0.0f, 400.0f));
      tg.setTransform(transform);

      // Create the canvas container.
      c_container = new Panel();
      c_container.setSize(360, 360);
      c_container.setLocation(0, 0);
      c_container.setVisible(true);
      c_container.setLayout(null);
      add(c_container);

      // Add the 2D and 3D canvases to the container.
      c_container.add(canvas3D);

      // Turn off the layout manager, widgets will be sized 
      // and positioned explicitly.
      setLayout(null);


      // Create the buttons.
/*      instruct_button = new Button("Introduction");
      instruct_button.setSize(135, 25);
      instruct_button.setLocation(10, 10);
      instruct_button.setVisible(true);
      instruct_button.addActionListener(this);
      b_container.add(instruct_button);		*/

      nNum = new TextField("5",20);
      nNum.setBackground(Color.white);
      Panel nPanel = new Panel();
      nPanel.setLayout(new BorderLayout(2,2));
      nPanel.setSize(70,20);
      nPanel.setLocation(380,50);
      nPanel.add( new Label(" n ="), BorderLayout.WEST );
      nPanel.add(nNum, BorderLayout.CENTER);
      nPanel.setVisible(true);
      add(nPanel);      
      
      hNum = new TextField("1",20);
      hNum.setBackground(Color.white);
      Panel hPanel = new Panel();
      hPanel.setLayout(new BorderLayout(2,2));
      hPanel.setSize(70,20);
      hPanel.setLocation(480,50);
      hPanel.add( new Label(" h ="), BorderLayout.WEST );
      hPanel.add(hNum, BorderLayout.CENTER);
      hPanel.setVisible(true);
      add(hPanel);     
      
      vNum = new TextField("1",20);
      vNum.setBackground(Color.white);
      Panel vPanel = new Panel();
      vPanel.setLayout(new BorderLayout(2,2));
      vPanel.setSize(70,20);
      vPanel.setLocation(580,50);
      vPanel.add( new Label(" v ="), BorderLayout.WEST );
      vPanel.add(vNum, BorderLayout.CENTER);
      vPanel.setVisible(true);
      add(vPanel);
	  
      HNum = new TextField("5",20);
      HNum.setBackground(Color.white);
      Panel HPanel = new Panel();
      HPanel.setLayout(new BorderLayout(2,2));
      HPanel.setSize(180,20);
      HPanel.setLocation(380,80);
      HPanel.add( new Label(" Height/Radius Ratio ="), BorderLayout.WEST );
      HPanel.add(HNum, BorderLayout.CENTER);
      HPanel.setVisible(true);
      add(HPanel);
	  
      // Create the button container.
      b_container = new Panel();
      b_container.setSize(270, 120);
      b_container.setLocation(380, 100);
      b_container.setVisible(true);
      b_container.setLayout(null);
	  
//public Scrollbar(int orientation, int value, int visible, int min, int max)
	  HSlider  = new Scrollbar(Scrollbar.HORIZONTAL, 10, 10, 0, 150);
	  HSlider.setUnitIncrement(2);	 
	  HSlider.setPageIncrement(10);	 
	  HSlider.addAdjustmentListener(this);
	  HSlider.setSize(200, 20);
	  HSlider.setLocation(10, 10);
	  b_container.add(HSlider);
	  
      update_button = new Button("Update");
      update_button.setSize(100, 20);
      update_button.setLocation(150, 50);
      update_button.setVisible(true);
      update_button.addActionListener(this);
      b_container.add(update_button);
      
      // Add the button container to the applet.
      add(b_container);
      

      // Create the "Introduction" panel.
      instruct_return_button = new Button("Return");
      instruct_return_button.setLocation(300, 370);
      instruct_return_button.setSize(120, 25);
      instruct_return_button.setVisible(false);
      instruct_return_button.addActionListener(this);
      instruct_text = 
         new TextArea(textString, 100, 200, TextArea.SCROLLBARS_VERTICAL_ONLY);
      instruct_text.setSize(715, 350);
      instruct_text.setLocation(0, 0);
      instruct_text.setVisible(false);
      add(instruct_text);

      add(instruct_return_button);   
   }

    public void destroy() {
	universe.cleanup();
    }

   /**
    *  Create the scenegraph for the 3D view.
    */
//   public BranchGroup createScene3D() {
   public void createScene3D() {

      // Define colors
      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 ambient = new Color3f(0.25f, 0.25f, 0.25f);
      Color3f diffuse = new Color3f(0.7f, 0.7f, 0.7f);
      Color3f specular = new Color3f(0.9f, 0.9f, 0.9f);
      Color3f ambientRed = new Color3f(0.2f, 0.05f, 0.0f);
      Color3f bgColor = new Color3f(0.05f, 0.05f, 0.2f);

      scene3D = new BranchGroup();
      scene3D.setCapability(BranchGroup.ALLOW_DETACH );
      // Create the bounding leaf node
      BoundingSphere bounds =
         new BoundingSphere(new Point3d(0.0,0.0,0.0), 1000.0);
      BoundingLeaf boundingLeaf = new BoundingLeaf(bounds);
      scene3D.addChild(boundingLeaf);

      // Create the background
      Background bg = new Background(bgColor);
      bg.setApplicationBounds(bounds);
      scene3D.addChild(bg);

      // Create the ambient light
      AmbientLight ambLight = new AmbientLight(white);
      ambLight.setInfluencingBounds(bounds);
      scene3D.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);
      scene3D.addChild(dirLight);

      // Create the transform group node
      TransformGroup transformGroup = new TransformGroup();
      transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
      transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
      scene3D.addChild(transformGroup);
      
      // Create the poles
      PrismaticPoles poles = new PrismaticPoles(zoom, n, h, v, H);
      transformGroup.addChild(poles.getChild());

      PickDragBehavior behavior = new PickDragBehavior(canvas3D, 
                                                       scene3D, transformGroup);
      behavior.setSchedulingBounds(bounds);
      transformGroup.addChild(behavior);

//      return branchGroup;
   }

  public void adjustmentValueChanged(AdjustmentEvent e){
     
    H = (double)HSlider.getValue()/10;
    HNum.setText(String.valueOf(H));
    scene3D.detach();
    createScene3D();
    universe.addBranchGraph(scene3D);
    canvas3D.repaint();
    
  }
  
   public void actionPerformed (ActionEvent event) {

      Object target = event.getSource();

      // Process the button events.
      if (target == instruct_return_button) {
         instruct_text.setVisible(false);
         instruct_return_button.setVisible(false);
         instruct_text.repaint();
         c_container.setVisible(true);
         b_container.setVisible(true);
      }
      else if (target == instruct_button) {
         c_container.setVisible(false);
         b_container.setVisible(false);
         instruct_text.setVisible(true);
         instruct_return_button.setVisible(true);
      }
      else if (target == update_button) {
         n = (int)Double.valueOf(nNum.getText()).doubleValue();
         h = (int)Double.valueOf(hNum.getText()).doubleValue();
         v = (int)Double.valueOf(vNum.getText()).doubleValue();
         H = (double)Double.valueOf(HNum.getText()).doubleValue();
         HSlider.setValue((int)(H*10));
         scene3D.detach();
         createScene3D();
      	 universe.addBranchGraph(scene3D);
         canvas3D.repaint();
      }

   }

   public void start() {
      if (appletFlag) showStatus("Symmetric Tensegrity of Symmetr Group S4");
   }


   /**
    *  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);
      }
   }

  /**
   *  Main method, only used when running as an application.
   */
  public static void main(String[] args) {
    Prismatic.appletFlag = false;
    new MainFrame(new Prismatic(), 730, 600);
  }
  
}

