/**
   * Set up the system properties needed to run the browser. This involves registering all the
   * properties needed for content and protocol handlers used by the URI system. Only needs to be
   * run once at startup.
   */
  private void setupProperties(final String textureQuality) {
    try {
      AccessController.doPrivileged(
          new PrivilegedExceptionAction() {
            public Object run() {
              String prop = System.getProperty("uri.content.handler.pkgs", "");
              if (prop.indexOf("vlc.net.content") == -1) {
                System.setProperty("uri.content.handler.pkgs", "vlc.net.content");
              }

              prop = System.getProperty("uri.protocol.handler.pkgs", "");
              if (prop.indexOf("vlc.net.protocol") == -1) {
                System.setProperty("uri.protocol.handler.pkgs", "vlc.net.protocol");
              }

              BrowserCore core = mainCanvas.getUniverse();
              WorldLoaderManager wlm = mainCanvas.getWorldLoaderManager();

              ContentHandlerFactory c_fac = URI.getContentHandlerFactory();

              if (!(c_fac instanceof VRMLContentHandlerFactory)) {
                c_fac = new VRMLContentHandlerFactory(core, wlm);
                URI.setContentHandlerFactory(c_fac);
              }

              FileNameMap fn_map = URI.getFileNameMap();
              if (!(fn_map instanceof VRMLFileNameMap)) {
                fn_map = new VRMLFileNameMap(fn_map);
                URI.setFileNameMap(fn_map);
              }

              if (textureQuality.equals("medium")) {
                System.setProperty("org.web3d.vrml.renderer.common.nodes.shape.useMipMaps", "true");
                System.setProperty(
                    "org.web3d.vrml.renderer.common.nodes.shape.anisotropicDegree", "2");
              } else if (textureQuality.equals("high")) {
                System.setProperty("org.web3d.vrml.renderer.common.nodes.shape.useMipMaps", "true");
                System.setProperty(
                    "org.web3d.vrml.renderer.common.nodes.shape.anisotropicDegree", "16");
              }

              return null;
            }
          });
    } catch (PrivilegedActionException pae) {
      console.warningReport(PROPERTY_SETUP_ERR, null);
    }
  }
  /**
   * Notification that a key is released.
   *
   * @param e The event that caused this method to be called
   */
  public void keyReleased(KeyEvent e) {
    switch (e.getKeyCode()) {
      case KeyEvent.VK_A:
        console.messageReport("Antialiasing not supported on Java3D yet.");
        /*
                        if((e.getModifiers() & KeyEvent.ALT_MASK) != 0) {

                            numSamples = numSamples * 2;

                            int max = getMaximumNumSamples();

                            // Busy wait till answer comes.  Should already be here
                            while(max < 0) {
                               try {
                                   Thread.sleep(50);
                               } catch(Exception e2) {}
                               max = getMaximumNumSamples();
                            }

                            if (numSamples > max)
                                numSamples = 1;

                            statusLabel.setText("Antialiasing samples: " + numSamples + " out of max: " + max);

                            caps.setSampleBuffers(true);
                            caps.setNumSamples(numSamples);

                            resetSurface();
                        }
        */
        break;

      case KeyEvent.VK_PAGE_DOWN:
        vpManager.nextViewpoint();
        break;

      case KeyEvent.VK_PAGE_UP:
        vpManager.previousViewpoint();
        break;

      case KeyEvent.VK_HOME:
        vpManager.firstViewpoint();
        break;

      case KeyEvent.VK_END:
        vpManager.lastViewpoint();
        break;

      case KeyEvent.VK_F:
        if ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0) {
          universe.setNavigationMode("FLY");
        }
        break;

      case KeyEvent.VK_W:
        if ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0) {
          universe.setNavigationMode("WALK");
        } else if ((e.getModifiers() & KeyEvent.ALT_MASK) != 0) {
          console.messageReport("Wireframe mode not supported on Java3D.");
        }
        break;

      case KeyEvent.VK_E:
        if ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0) {
          universe.setNavigationMode("EXAMINE");
        }
        break;

      case KeyEvent.VK_Z:
        if ((e.getModifiers() & KeyEvent.ALT_MASK) != 0) {
          // Enter/Exit Elumens mode
          elumensMode = !elumensMode;

          // JC: We're not dealing with this right now.
          //                    resetSurface();
        }
        break;
    }
  }
  /**
   * Create an instance of the panel configured to show or hide the controls and only shows VRML97
   * content.
   *
   * @param showDash true to show the navigation bar
   * @param dashTop true to put the nav bar at the top
   * @param showUrl true to show the URL location bar
   * @param urlTop true to put the location bar at the top
   * @param urlReadOnly true to make the location bar read only
   * @param showConsole true if the console should be shown immediately
   * @param skinProperties The properties object to configure appearance with
   * @param showStatusBar true to show a status bar
   * @param showFPS true to show the current FPS
   * @param contentDirectory initial directory to load content from. Must be a full path.
   * @param antialiased true to turn on antialiasing
   * @param antialiasingQuality low, medium, high, antialiasing must be turned on for this to
   *     matter.
   * @param primitiveQuality low, medium, high.
   * @param textureQuality low, medium, high.
   * @param skinProperties Customisation of the browser buttons etc
   */
  public BrowserJPanel(
      boolean showDash,
      boolean dashTop,
      boolean showUrl,
      boolean urlTop,
      boolean urlReadOnly,
      boolean showConsole,
      boolean showOpenButton,
      boolean showReloadButton,
      boolean showStatusBar,
      boolean showFPS,
      String contentDirectory,
      boolean antialiased,
      String antialiasingQuality,
      String primitiveQuality,
      String textureQuality,
      Properties skinProperties) {

    super(new BorderLayout());

    setSize(800, 600);

    numSamples = 1;
    frameCycleTime = -1;
    wireframe = false;
    elumensMode = false;

    // JC: Copied from the OpenGL code, so does nothing right now.
    if (antialiased) {
      if (antialiasingQuality.equals("low")) {
        numSamples = 2;
        //                caps.setNumSamples(numSamples);
      } else if (antialiasingQuality.equals("medium")) {
        // TODO: Really need to find the max allowable.  But JOGL startup issues make this a problem
        System.out.println("Trying for 4 samples of antialiasing.");
        numSamples = 4;
        //                caps.setNumSamples(numSamples);
      } else if (antialiasingQuality.equals("high")) {
        System.out.println("Trying for 8 samples of antialiasing.");
        numSamples = 8;
        //                caps.setNumSamples(numSamples);
      }
    }

    console = new SwingConsoleWindow();
    console.messageReport("Initializing Java3D VRML browser.\n");

    addComponentListener(this);

    // We also need a canvas to display stuff with and a universe to set
    // the content in.
    GraphicsConfigTemplate3D template = new GraphicsConfigTemplate3D();
    template.setDoubleBuffer(GraphicsConfigTemplate3D.REQUIRED);
    GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice dev = env.getDefaultScreenDevice();

    GraphicsConfiguration gfx_cfg = dev.getBestConfiguration(template);

    mainCanvas = new VRMLBrowserCanvas(gfx_cfg, true);
    mainCanvas.initialize();
    mainCanvas.setErrorReporter(console);

    j3dCanvas = mainCanvas;

    CursorManager cm = new CursorManager(mainCanvas, skinProperties, console);

    universe = mainCanvas.getUniverse();
    universe.addSensorStatusListener(cm);
    universe.addNavigationStateListener(cm);

    vpManager = mainCanvas.getViewpointManager();

    setupProperties(textureQuality);

    eaiBrowser = new EAIBrowser(universe, browserImpl, eventQueue, console);

    add(mainCanvas, BorderLayout.CENTER);

    // Create these all the time
    statusLabel = new JLabel();
    fpsLabel = new JLabel();
    SwingLocationToolbar tb = null;

    if (showUrl) {
      tb =
          new SwingLocationToolbar(
              universe,
              mainCanvas.getWorldLoaderManager(),
              urlReadOnly,
              showOpenButton,
              showReloadButton,
              contentDirectory,
              skinProperties,
              console);

      if (urlTop) add(tb, BorderLayout.NORTH);
      else add(tb, BorderLayout.SOUTH);
    }

    // Need to fix this as this panel will trash the existing one if they are
    // both at the top or bottom.

    if (showDash) {
      JPanel p2 = new JPanel(new BorderLayout());

      if (dashTop) add(p2, BorderLayout.NORTH);
      else add(p2, BorderLayout.SOUTH);

      navToolbar = new SwingNavigationToolbar(universe, skinProperties, console);
      // navToolbar.setAllowUserStateChange(true);
      SwingViewpointToolbar vp_tb =
          new SwingViewpointToolbar(universe, vpManager, skinProperties, console);

      SwingConsoleButton console_button = new SwingConsoleButton(console, skinProperties);

      p2.add(navToolbar, BorderLayout.WEST);
      p2.add(vp_tb, BorderLayout.CENTER);
      p2.add(console_button, BorderLayout.EAST);

      if (showFPS || showStatusBar) {
        statusBar = new SwingStatusBar(universe, showStatusBar, showFFS, skinProperties, console);

        if (tb != null) {
          tb.setProgressListener(statusBar.getProgressListener());
        }

        p2.add(statusBar, BorderLayout.SOUTH);
      }
    }

    if (showConsole) console.setVisible(true);
  }