/*******************************************************************************
*                                                                              *
*  File:        LuaJava.java                            Revision:  1.0         *
*                                                                              *
*  Contents:    the author's runtime environment for LuaJava                   *
*                                                                              *
*  Creation:    03.10.2004                     Last Modification:  19.11.2004  *
*                                                                              *
*  Platform:    IBM-compatible PC running Windows 98SE                         *
*                                                                              *
*  Environment: Java 1.4                                                       *
*                                                                              *
*  Author:      Andreas Rozek           Phone:  ++49 (7031) 222305             *
*               Bunsenstraße 80/1       Fax:    -                              *
*             D-71032 Böblingen         EMail:  Info@Andreas-Rozek.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)                                                         *
*                                                                              *
*******************************************************************************/

package luna;

import java.io.*;                            // Java file handling and stream IO
import java.net.*;                                       // Java network support

import luajava.*;                             // a "bridge" between Lua and Java

public class LuaJava {

/*******************************************************************************
*                                                                              *
*                          Non-Public Class Constants                          *
*                                                                              *
*******************************************************************************/

  final static int ERRERR    = LuaState.LUA_ERRERR.intValue();
  final static int ERRFILE   = LuaState.LUA_ERRFILE.intValue();
  final static int ERRMEM    = LuaState.LUA_ERRMEM.intValue();
  final static int ERRRUN    = LuaState.LUA_ERRRUN.intValue();
  final static int ERRSYNTAX = LuaState.LUA_ERRSYNTAX.intValue();

/*******************************************************************************
*                                                                              *
*                            Public Class Variables                            *
*                                                                              *
*******************************************************************************/

  public static LuaState  Lua;      // stores the sole Lua state in this context
  public static LuaObject LuaArgList;    // list of arguments for the Lua script

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

/*******************************************************************************
*                                                                              *
* showUsage                     prints some usage information for this program *
*                                                                              *
*******************************************************************************/

  static void showUsage () {
    System.out.println("LuaJava - a Java-based runtime environment for Lua scripts");
    System.out.println();
    System.out.println("Usage: LuaJava <script> [<argument> ...]");
    System.out.println("Key:");
    System.out.println(" <script>   the name of the Lua script file to be executed");
    System.out.println(" <argument> command line argument for the Lua script");
  };

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

/*******************************************************************************
*                                                                              *
* doFile                                    executes the given Lua script file *
*                                                                              *
*******************************************************************************/

  static void doFile (String ScriptFile) {
    int ReturnCode = Lua.doFile(ScriptFile);
    if (ReturnCode != 0) {
      if        (ReturnCode == LuaState.LUA_ERRERR.intValue()) {
        System.err.println("Lua error in error handler");
      } else if (ReturnCode == LuaState.LUA_ERRFILE.intValue()) {
        System.err.println("Lua file error");
      } else if (ReturnCode == LuaState.LUA_ERRMEM.intValue()) {
        System.err.println("Lua memory allocation error");
      } else if (ReturnCode == LuaState.LUA_ERRRUN.intValue()) {
        System.err.println("Lua runtime error");
      } else if (ReturnCode == LuaState.LUA_ERRSYNTAX.intValue()) {
        System.err.println("Lua syntax error");
      } else {
        System.err.println("Lua error code " + ReturnCode);
      };

      System.err.println("while executing file " + ScriptFile);
    };
  };

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

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

  public static void main (String[] ArgList) {
    String ScriptFile = "";      // stores the name of the given Lua script file

    try {

    /**** the first given argument specifies which Lua script file to execute ****/

      int ArgLength = ArgList.length;
      if (ArgLength == 0) {
        showUsage();                          // explain how to use this program
        System.exit(0);
      };

      ScriptFile = ArgList[0];

    /**** initialize LuaJava ****/

      Lua = LuaStateFactory.newLuaState();
        Lua.openBasicLibraries();
        Lua.openDebug();
        Lua.openLoadLib();

    /**** provide an "exit" function ****/

      JavaFunction exit = new JavaFunction (Lua) {
        public int foo () throws LuaException {
          LuaState Lua = this.L;                         // just an abbreviation
            if (Lua.getTop() == 1) {
              System.exit(0);
            } else {
              System.exit((int) getParam(2).getNumber());           // may fail!
            };
          return 0;
        };
      };
      exit.register("exit");                  // declare the function within Lua

    /**** provide functions to access stdout and stderr ****/

      JavaFunction print = new JavaFunction (Lua) {
        public int foo () throws LuaException {
          LuaState Lua = this.L;                         // just an abbreviation
            int ArgCount = Lua.getTop();                                 // dto.
            for (int i = 2; i <= ArgCount; i++) {
              LuaObject Argument = getParam(i);          // just an abbreviation
                Argument.push(); int ArgType = Lua.type(-1);
              if (ArgType == Lua.LUA_TNUMBER.intValue()) {
                double Number  = Argument.getNumber();
                long   Integer = Math.round(Number);
                if ((double) Integer == Number) {    // check proper conversion!
                  System.out.print(Integer);                // output as integer
                } else {
                  System.out.print(Argument); // use LuaObject's toString method
                };
              } else if (ArgType == Lua.LUA_TSTRING.intValue()) {
                System.out.print(Argument.getString());
              } else {
                System.out.print(Argument);
              };
            };
          return 0;
        };
      };
      print.register("print");                // declare the function within Lua
      print.register("say");                                   // just a synonym

      JavaFunction println = new JavaFunction (Lua) {
        public int foo () throws LuaException {
          LuaState Lua = this.L;                         // just an abbreviation
            int ArgCount = Lua.getTop();                                 // dto.
            for (int i = 2; i <= ArgCount; i++) {
              LuaObject Argument = getParam(i);          // just an abbreviation
                Argument.push(); int ArgType = Lua.type(-1);
              if (ArgType == Lua.LUA_TNUMBER.intValue()) {
                double Number  = Argument.getNumber();
                long   Integer = Math.round(Number);
                if ((double) Integer == Number) {    // check proper conversion!
                  System.out.print(Integer);                // output as integer
                } else {
                  System.out.print(Argument); // use LuaObject's toString method
                };
              } else if (ArgType == Lua.LUA_TSTRING.intValue()) {
                System.out.print(Argument.getString());
              } else {
                System.out.print(Argument);
              };
            };

            System.out.println();
          return 0;
        };
      };
      println.register("println");            // declare the function within Lua
      println.register("sayln");                               // just a synonym

      JavaFunction cry = new JavaFunction (Lua) {
        public int foo () throws LuaException {
          LuaState Lua = this.L;                         // just an abbreviation
            int ArgCount = Lua.getTop();                                 // dto.
            for (int i = 2; i <= ArgCount; i++) {
              LuaObject Argument = getParam(i);          // just an abbreviation
                Argument.push(); int ArgType = Lua.type(-1);
              if (ArgType == Lua.LUA_TNUMBER.intValue()) {
                double Number  = Argument.getNumber();
                long   Integer = Math.round(Number);
                if ((double) Integer == Number) {    // check proper conversion!
                  System.out.print(Integer);                // output as integer
                } else {
                  System.out.print(Argument); // use LuaObject's toString method
                };
              } else if (ArgType == Lua.LUA_TSTRING.intValue()) {
                System.out.print(Argument.getString());
              } else {
                System.out.print(Argument);
              };
            };
          return 0;
        };
      };
      cry.register("complain");               // declare the function within Lua
      cry.register("cry");                                     // just a synonym

      JavaFunction cryln = new JavaFunction (Lua) {
        public int foo () throws LuaException {
          LuaState Lua = this.L;                         // just an abbreviation
            int ArgCount = Lua.getTop();                                 // dto.
            for (int i = 2; i <= ArgCount; i++) {
              LuaObject Argument = getParam(i);          // just an abbreviation
                Argument.push(); int ArgType = Lua.type(-1);
              if (ArgType == Lua.LUA_TNUMBER.intValue()) {
                double Number  = Argument.getNumber();
                long   Integer = Math.round(Number);
                if ((double) Integer == Number) {    // check proper conversion!
                  System.out.print(Integer);                // output as integer
                } else {
                  System.out.print(Argument); // use LuaObject's toString method
                };
              } else if (ArgType == Lua.LUA_TSTRING.intValue()) {
                System.out.print(Argument.getString());
              } else {
                System.out.print(Argument);
              };
            };

            System.err.println();
          return 0;
        };
      };
      cryln.register("complainln");           // declare the function within Lua
      cryln.register("cryln");                                 // just a synonym

    /**** look for an (optional) "profile" script and run it ****/

      URL ProfileURL = LuaJava.class.getResource("LuaJava.lua");
      if (ProfileURL != null) {
        String Profile = ProfileURL.getPath().replace('/',File.separatorChar);
        if (Profile.startsWith("\\")) {                 // windows speciality...
          Profile = Profile.substring(1);
        };

        if (Profile.equals("")) {       // the error handling is poor, I know...
          System.err.println("LuaJava profile missing");
          System.exit(1);
        } else {
          doFile(Profile);
        };
      };

    /**** any extra command line arguments should be passed to the Lua script ****/

      Lua.newTable();           // create a Lua table with these extra arguments
        for (int i = 1; i < ArgLength; i++) {
          Lua.pushNumber((double) i); Lua.pushString(ArgList[i]); Lua.rawSet(1);
        };
        Lua.pushString("n"); Lua.pushNumber((double) (ArgLength-1)); Lua.rawSet(1);
      LuaArgList = Lua.getLuaObject(1); Lua.pop(1);

      JavaFunction getargs = new JavaFunction (Lua) {
        public int foo () throws LuaException {
          LuaState Lua = this.L;                         // just an abbreviation
            Lua.pushObjectValue(LuaArgList);   // pass argument list over to Lua
          return 1;
        };
      };
      getargs.register("getargs");            // declare the function within Lua

    /**** now evaluate the given script ****/

      doFile(ScriptFile);
    } catch (Exception Signal) {
      System.err.println("error in evaluation of " + ScriptFile);
      Signal.printStackTrace();
    };
  };
};

