/*******************************************************************************
*                                                                              *
*  File:        Rhino_11.java                           Revision:  1.0         *
*                                                                              *
*  Purpose:     creates JavaScript objects from within Java and tests them un- *
*               der JavaScript                                                 *
*                                                                              *
*  Creation:    01.11.2001                     Last Modification:  01.11.2001  *
*                                                                              *
*  Platform:    IBM-compatible PC running Windows 98SE                         *
*                                                                              *
*  Environment: Java 1.3                                                       *
*                                                                              *
*  Author:      Andreas Rozek           Phone:  ++49 (711) 6770682             *
*               Kirschblütenweg 15      Fax:    -                              *
*             D-70569 Stuttgart         EMail:  Andreas.Rozek@T-Online.De      *
*               Germany                                                        *
*                                                                              *
*  URL:         http://www.Andreas-Rozek.de/                                   *
*                                                                              *
*  Copyright:   this software is published under the  "GNU Lesser General Pub- *
*               lic  License"  (see  "http://www.fsf.org/copyleft/lesser.html" *
*               for additional information)                                    *
*                                                                              *
*  Comments:    (none)                                                         *
*                                                                              *
*******************************************************************************/

import java.io.*;                            // Java file handling and stream IO
import org.mozilla.javascript.*;                   // Rhino distribution classes

public class Rhino_11 extends ScriptableObject {

/*******************************************************************************
*                                                                              *
*                          Non-Public Class Variables                          *
*                                                                              *
*******************************************************************************/

  static Rhino_11 Global;            // refers to the JavaScript "Global" object
  static Object   undefined;      // shortcut referring to the "undefined" value

/*******************************************************************************
*                                                                              *
*                             Public Class Methods                             *
*                                                                              *
*******************************************************************************/

/*******************************************************************************
*                                                                              *
* evaluateFile          evaluates the contents of a given (script source) file *
*                                                                              *
*******************************************************************************/

  public static void evaluateFile (Context actualContext, String FileName) {
    FileReader InStream = null;
    try {
      InStream = new FileReader(FileName);
      actualContext.evaluateReader(Global, InStream, FileName, 1, null);
    } catch (FileNotFoundException Signal) {
      Context.reportError(
        "unable to open file \"" + FileName + "\" (reason: \"" + Signal.getMessage() + "\")"
      );
    } catch (WrappedException Signal) {
      Context.reportError(
        "WrappedException while evaluating file \"" + FileName +
        "\" (reason: \"" + Signal.getMessage() + "\")"
      );
    } catch (EvaluatorException Signal) {
      Context.reportError(
        "EvaluatorException while evaluating file \"" + FileName +
        "\" (reason: \"" + Signal.getMessage() + "\")"
      );
    } catch (JavaScriptException Signal) {
      Context.reportError(
        "JavaScriptException while evaluating file \"" + FileName +
        "\" (reason: \"" + Signal.getMessage() + "\")"
      );
    } catch (IOException Signal) {
      Context.reportError(
        "error while reading file \"" + FileName + "\" (reason: \"" + Signal.getMessage() + "\")"
      );
    } finally {
      try {
        if (InStream != null) InStream.close();
      } catch (Exception Signal) {
        /* nop */
      };
    };
  };

/*******************************************************************************
*                                                                              *
* evaluateString               evaluates the contents of a given script source *
*                                                                              *
*******************************************************************************/

  public static void evaluateString (Context actualContext, String SourceText) {
    try {
      actualContext.evaluateString(Global, SourceText, "Rhino_11", 1, null);
    } catch (WrappedException Signal) {
      Context.reportError(
        "WrappedException while evaluating the internal script source " +
        "(reason: \"" + Signal.getMessage() + "\")"
      );
    } catch (EvaluatorException Signal) {
      Context.reportError(
        "EvaluatorException while evaluating the internal script source " +
        "(reason: \"" + Signal.getMessage() + "\")"
      );
    } catch (JavaScriptException Signal) {
      Context.reportError(
        "JavaScriptException while evaluating the internal script source " +
        "(reason: \"" + Signal.getMessage() + "\")"
      );
    };
  };

/*******************************************************************************
*                                                                              *
* exit                             leaves the shell with the given return code *
*                                                                              *
*******************************************************************************/

  public static void exit (
    Context actualContext, Scriptable actualObject, Object[] ArgList, Function FunctionContext
  ) {
    if        (ArgList.length == 0) {
      java.lang.System.exit(0);
    } else if (ArgList.length != 1) {
      throw new IllegalArgumentException("exit(code) called with more than one argument");
    } else if (ArgList[0] == undefined) {
      throw new IllegalArgumentException("exit(code) called with an undefined argument");
    } else {
      double ReturnCode = Context.toNumber(ArgList[0]);
      if (Double.isNaN(ReturnCode)) {
        throw new IllegalArgumentException("exit(code) called with non-numeric argument");
      } else if (Double.isInfinite(ReturnCode) || (ReturnCode < Integer.MIN_VALUE) || (ReturnCode > Integer.MAX_VALUE)) {
        throw new IllegalArgumentException("exit(code) called with infinite numeric argument");
      } else {
        java.lang.System.exit((int) ReturnCode);
      };
    };
  };

/*******************************************************************************
*                                                                              *
* main                                                            main program *
*                                                                              *
*******************************************************************************/

  public static void main (String ArgList[]) {
    if (ArgList.length != 0) {
      complainln("Warning: any given command line arguments will be ignored");
    };

  /**** prepare Rhino execution environment ****/

    Global = new Rhino_11();        // let "Rhino_11" become the "Global" object

    Context ScriptContext = Context.enter();
      Scriptable ScriptScope = ScriptContext.initStandardObjects(Global);

      undefined = ScriptContext.getUndefinedValue();

    /**** register internal functions ****/

      String[] NameList = {"exit", "print", "println"};
      try {
        Global.defineFunctionProperties(NameList, Rhino_11.class, ScriptableObject.DONTENUM);
      } catch (PropertyException Signal) {
        complainln("unable to register global shell functions");
        exit(-1);
      };

    /**** now create various JavaScript objects ****/

      Global.put("aBoolean",  Global, new Boolean(true));
      Global.put("aByte",     Global, new Byte   ((byte) 1));
      Global.put("aShort",    Global, new Short  ((short) 2));
      Global.put("anInteger", Global, new Integer(3));
      Global.put("aLong",     Global, new Long   (4));
      Global.put("aFloat",    Global, new Float  (5.0));
      Global.put("aDouble",   Global, new Double (6.0));
      Global.put("aString",   Global, new String ("(anything)"));
      Global.put("anArray",   Global, ScriptContext.newArray(Global,
        new Object[] {new Boolean(true), new Byte((byte) 1), new Short((short) 2),
          new Integer(3), new Long(4), new String("(anything)")}
      ));
      Global.put("aJavaArray",    Global, new int[] {0,1,2,3,4});
      Global.put("aSilentObject", Global, new SilentObject());
      Global.put("aGossipObject", Global, new GossipObject());
      Global.put("aBeanObject",   Global, new BeanObject());

      try {
        Scriptable UserObject = ScriptContext.newObject(Global);
          ScriptableObject.putProperty(UserObject, "aBoolean",  new Boolean(true));
          ScriptableObject.putProperty(UserObject, "aByte",     new Byte   ((byte) 1));
          ScriptableObject.putProperty(UserObject, "aShort",    new Short  ((short) 2));
          ScriptableObject.putProperty(UserObject, "anInteger", new Integer(3));
          ScriptableObject.putProperty(UserObject, "aLong",     new Long   (4));
          ScriptableObject.putProperty(UserObject, "aFloat",    new Float  (5.0));
          ScriptableObject.putProperty(UserObject, "aDouble",   new Double (6.0));
          ScriptableObject.putProperty(UserObject, "aString",   new String ("(anything)"));
          ScriptableObject.putProperty(UserObject, "anArray",   ScriptContext.newArray(Global,3));
        Global.put("anUserObject", Global, UserObject);
      } catch (Exception Signal) {
        complainln("error while creating an \"UserObject\"");
        complainln("(reason: \"" + Signal.getMessage() + "\")");
        exit(-1);
      };

    /**** and test their appearance under JavaScript ****/

      evaluateFile(ScriptContext,"Rhino_11.js");
    ScriptContext.exit();

  /**** that's it! ****/

    exit(0);
  };

/*******************************************************************************
*                                                                              *
* print, println                       print the given arguments onto "stdout" *
*                                                                              *
*******************************************************************************/

  public static void print (
    Context actualContext, Scriptable actualObject, Object[] ArgList, Function FunctionContext
  ) {
    for (int i = 0; i < ArgList.length; i++) { // don't worry about "undefined" arguments
      java.lang.System.out.print(Context.toString(ArgList[i]));
    };
  };


  public static void println (
    Context actualContext, Scriptable actualObject, Object[] ArgList, Function FunctionContext
  ) {
    print(actualContext,actualObject,ArgList,FunctionContext);
    java.lang.System.out.println();
  };

/*******************************************************************************
*                                                                              *
*                           Non-Public Class Methods                           *
*                                                                              *
*******************************************************************************/

/*******************************************************************************
*                                                                              *
* complain, complainln                   print the given message onto "stderr" *
*                                                                              *
*******************************************************************************/

  static void complain (String Message) {
    java.lang.System.out.print(Message);
  };

  static void complainln () {
    java.lang.System.out.println();
  };

  static void complainln (String Message) {
    java.lang.System.out.println(Message);
  };

/*******************************************************************************
*                                                                              *
* exit                           leaves the program with the given return code *
*                                                                              *
*******************************************************************************/

  static void exit (int ReturnCode) {
    java.lang.System.exit(ReturnCode);
  };

/*******************************************************************************
*                                                                              *
* print, println                         print the given message onto "stdout" *
*                                                                              *
*******************************************************************************/

  static void print (String Message) {
    java.lang.System.out.print(Message);
  };

  static void println () {
    java.lang.System.out.println();
  };

  static void println (String Message) {
    java.lang.System.out.println(Message);
  };

/*******************************************************************************
*                                                                              *
*                           Public Instance Methods                            *
*                                                                              *
*******************************************************************************/

/*******************************************************************************
*                                                                              *
* getClassName                yields the (Rhino-internal) name of this "class" *
*                                                                              *
*******************************************************************************/

  public String getClassName () {
   return "global";
  };

/*******************************************************************************
*                                                                              *
*                           Additional Inner Classes                           *
*                                                                              *
*******************************************************************************/

/*******************************************************************************
*                                                                              *
*      BeanObject - a simple Java Bean object to be passed to JavaScript       *
*                                                                              *
*******************************************************************************/

  public static class BeanObject {
    boolean aBoolean  = true;
    byte    aByte     = 1;
    short   aShort    = 2;
    int     anInteger = 3;
    long    aLong     = 4;
    float   aFloat    = 5.0f;
    double  aDouble   = 6.0;
    String  aString   = "(anything)";

    public boolean getaBoolean()  {return aBoolean;};
    public byte    getaByte()     {return aByte;};
    public short   getaShort()    {return aShort;};
    public int     getanInteger() {return anInteger;};
    public long    getaLong()     {return aLong;};
    public float   getaFloat()    {return aFloat;};
    public double  getaDouble()   {return aDouble;};
    public String  getaString()   {return aString;};

    public String toString() {
      return aBoolean + ", " + aByte  + ", " + aShort  + ", " + anInteger + ", " +
             aLong    + ", " + aFloat + ", " + aDouble + ", \"" + aString + "\"";
    };
  };

/*******************************************************************************
*                                                                              *
*          GossipObject - a simple object to be passed to JavaScript           *
*                                                                              *
*******************************************************************************/

  public static class GossipObject {
    public boolean aBoolean  = true;
    public byte    aByte     = 1;
    public short   aShort    = 2;
    public int     anInteger = 3;
    public long    aLong     = 4;
    public float   aFloat    = 5.0f;
    public double  aDouble   = 6.0;
    public String  aString   = "(anything)";

    public String toString() {
      return aBoolean + ", " + aByte  + ", " + aShort  + ", " + anInteger + ", " +
             aLong    + ", " + aFloat + ", " + aDouble + ", \"" + aString + "\"";
    };
  };

/*******************************************************************************
*                                                                              *
*          SilentObject - a simple Java object with hidden properties          *
*                                                                              *
*******************************************************************************/

  public static class SilentObject {
    boolean aBoolean  = true;
    byte    aByte     = 1;
    short   aShort    = 2;
    int     anInteger = 3;
    long    aLong     = 4;
    float   aFloat    = 5.0f;
    double  aDouble   = 6.0;
    String  aString   = "(anything)";

    public String toString() {
      return aBoolean + ", " + aByte  + ", " + aShort  + ", " + anInteger + ", " +
             aLong    + ", " + aFloat + ", " + aDouble + ", \"" + aString + "\"";
    };
  };
};

