/*
 * VRwavePlugin.java
 * Netscape Plugin wrapper around VRwave
 *
 * created: mpichler, 19970812
 *
 * changed: mpichler, 19970924
 *
 * $Id: VRwavePlugin.java,v 1.8 1997/09/24 15:26:26 mpichler Exp $
 */


import netscape.plugin.Plugin;  // moz3_0.zip

import java.net.URL;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

import iicm.vrml.vrwave.*;  // VRwave core classes
import vrml.external.Browser;  // Java-EAI


/**
 * depending on whether Browser already extends Plugin or not,
 * VRwavePlugin has to extend Browser or Plugin. In the first case,
 * Browser location via JavaScript code will work too, otherwise only
 * the clean interface of Browser.getBrowser will do so.
 */

public class VRwavePlugin extends Browser /*Plugin*/
{
  Scene scene_;  // my scene
  SceneFrame sceneframe_;
  PipedInputStream pin_;  // to read data out of the pipe
  PipedOutputStream pout_;  // to write data into the pipe
  Thread rthread_;  // reader thread (parsing)
  VRwaveReader vrreader_;
  static final boolean DEBUG = true;

  /**
   * initialize plug-in instance: start VRwave
   */

  public void init ()
  {
    System.out.println (VRwave.STARTUP);

    if (DEBUG)
      System.err.println ("Plugin.init was called");

    try
    {
      scene_ = new Scene (null);
      // TODO: where to load properties from?
    }
    catch (Throwable t)
    {
      System.err.println ("Error: " + t);
    }
  } // init

  /**
   * create scene frame
   * @param home VRWAVE_HOME to load icons.gif (later also font files etc.)
   */

  void createSceneFrame (String home)
  {
    try
    {
      VRwave.setHome ("file:" + home);  // must read from URL instead of file
      sceneframe_ = new SceneFrame ("VRwave", scene_, true);  // shows itself
    }
    catch (Throwable t)
    {
      System.err.println ("Error: " + t);
    }
  } // createSceneFrame

  /**
   * plug-in gets unloaded: quit VRwave
   */

  public void destroy ()
  {
    if (DEBUG)
      System.err.println ("Plugin.destroy was called");

    if (rthread_ != null && rthread_.isAlive ())
    {
      if (DEBUG)
        System.err.println ("stopping reader thread");
      rthread_.stop ();
    }

    if (scene_ != null)
    {
      try
      {
        if (DEBUG)
          System.err.println ("clearScene");
        Browser.stopVRwave (scene_);
        scene_.clearScene ();  // stop all scene activity
        if (sceneframe_ != null)
        {
          if (sceneframe_.isVisible ())
            sceneframe_.hide ();
          sceneframe_.dispose ();  // free frame resources
        }
        if (DEBUG)
          System.err.println ("Frame closed");
        scene_ = null;
        sceneframe_ = null;
      }
      catch (Throwable t)
      {
        System.err.println ("Error: " + t);
      }
    }
  } // destroy

  /**
   * start a thread to read streamed data.
   */

  public void startReading (String baseurl)
  {
    try
    {
      pin_ = new PipedInputStream ();
      pout_ = new PipedOutputStream (pin_);
      rthread_ = new Thread (vrreader_ = new VRwaveReader (scene_, pin_, baseurl));
      rthread_.start ();
    }
    catch (Throwable t)
    {
      System.err.println ("Error: " + t);
    }
  }

  /**
   * called when input is complete or to abort reading.
   */

  public void dataComplete ()
  {
    try
    {
      pout_.close ();
      // data are complete sent in pipe, parsing of buffered data has not yet finished
    }
    catch (Throwable t)
    {
      System.err.println ("Error: " + t);
    }
    // reader thread is not stopped here - give parser time to complete,
    // will complain about premature EOF itself when data is incomplete
  }

  /**
   * tell how many bytes can be read by readData without blocking.
   * only valid between startReading and dataComplete calls.
   */

  public int readableData ()
  {
    // PipedIOStreams have no method to get this information.
    // following code assumes a buffer size of at least 1024
    // which the PipedInputStream can fill without blocking.
    // method currently not unused.

    try
    {
      int inbuf = pin_.available ();  // >= 0
      if (inbuf > 1024)  // oops
        return 0;
      return (1024 - inbuf);
    }
    catch (Throwable t)
    {
      System.err.println ("Error: " + t);
      return 0;
    }
  } // readableData

  /**
   * read some chunk of data (by writing it into the pipe).
   * only valid between startReading and dataComplete calls.
   * be very careful not to lock netscape in this method.
   */

  public void readData (byte[] data, int len)
  {
    try
    {
      if (scene_ != null && vrreader_ != null && vrreader_.acceptdata_)
        pout_.write (data, 0, len);
    }
    catch (Throwable t)
    {
      System.err.println ("Error: " + t);
    }
  }

} // VRwavePlugin
