package org.plenix.jsp.language;

import FESI.jslib.*;
import java.util.Enumeration;
import javax.servlet.http.*;

import org.plenix.jsp.language.*;

public class ScriptedLanguage extends LanguageProcessorImpl
{
  // Members
  String initScript;
  String compileScript;
  String loadScript;
  String unloadScript;
  String executeScript;

  JSGlobalObject evaluator;

  private static String[] extensions =
  {
    "FESI.Extensions.BasicIO",
    "FESI.Extensions.FileIO",
    "FESI.Extensions.JavaAccess",
    "FESI.Extensions.Database",
    "FESI.Extensions.OptionalRegExp"
  };

  public ScriptedLanguage()
    throws LanguageException
  {
    super();

    try
    {
      evaluator = JSUtil.makeEvaluator(extensions);

      // Passes language parameters to evaluator
      Enumeration e = getParameterNames();
      JSObject parameters = evaluator.makeJSObject();

      while (e.hasMoreElements())
      {
        String name = (String) e.nextElement();
	String value = this.getParameter(name);

	parameters.setMember(name, value);
      }

      parameters.setMember("sourceExtension", this.getSourceExtension());

      evaluator.setMember("parameters" , parameters);
    }
    catch (JSException e)
    {
      throw new LanguageException("Language '" + getName() + "': Error in evaluator creation.\n" + e.getMessage());
    }
  }

  // Program instance services
  public void init(String path)
    throws LanguageException
  {
    if (initScript != null)
    {
      try
      {
        evaluator.evalAsFunction("init('" + path + "');");
      }
      catch (JSException e)
      {
        throw new LanguageException("Language '" + getName() + "': Error during init.\n" + e.getMessage());
      }
    }
  }

  public void compile(String baseName, String path)
    throws LanguageException
  {
    if (compileScript != null)
    {
      try
      {
        evaluator.evalAsFunction("compileProgram('" + baseName + "', '" + path + "');");
      }
      catch (JSException e)
      {
        throw new LanguageException("Language '" + getName() + "': Error during compilation.\n" + e.getMessage());
      }
    }
  }

  public Object load(String baseName, String path)
    throws LanguageException
  {
    if (loadScript == null)
    {
      throw new LanguageException("Language '" + getName() + "': No load script provided");
    }

    try
    {
      return evaluator.evalAsFunction("loadProgram('" + baseName + "', '" + path + "');");
    }
    catch (JSException e)
    {
      throw new LanguageException("Language '" + getName() + "': Error during loading.\n" + e.getMessage());
    }
  }

  public void unload(Object program)
    throws LanguageException
  {
    if (unloadScript != null)
    {
      if (program == null)
      {
        throw new LanguageException("Language '" + getName() + "': Null argument handed to unload");
      }

      try
      {
        evaluator.setMember("programInstance", evaluator.makeObjectWrapper(program));
        evaluator.evalAsFunction("unloadProgram(programInstance);");
      }
      catch (JSException e)
      {
        throw new LanguageException("Language '" + getName() + "': Error during unloading.\n" + e.getMessage());
      }
    }
  }

  public void execute(Object program, HttpServletRequest request, HttpServletResponse response)
    throws LanguageException
  {
    if (executeScript == null)
    {
      throw new LanguageException("Language '" + getName() + "': No execute script provided");
    }

    if (program == null)
    {
      throw new LanguageException("Language '" + getName() + "': Null argument handed to execute");
    }

    try
    {
      evaluator.setMember("programInstance", evaluator.makeObjectWrapper(program));
      evaluator.setMember("servletrequest", evaluator.makeObjectWrapper(request));
      evaluator.setMember("servletresponse", evaluator.makeObjectWrapper(response));

      evaluator.evalAsFunction("executeProgram(programInstance, servletrequest, servletresponse);");
    }
    catch (JSException e)
    {
      throw new LanguageException("Language '" + getName() + "': Error during execution.\n" + e.getMessage());
    }
  }

  // Builders
  public void setInitScript(String script)
    throws JSException
  {
    initScript = evalScript(script);
  }

  public void setCompileScript(String script)
    throws JSException
  {
    compileScript = evalScript(script);
  }

  public void setLoadScript(String script)
    throws JSException
  {
    loadScript = evalScript(script);
  }

  public void setUnloadScript(String script)
    throws JSException
  {
    unloadScript = evalScript(script);
  }

  public void setExecuteScript(String script)
    throws JSException
  {
    executeScript = evalScript(script);
  }

  private String evalScript(String script)
    throws JSException
  {
    if (script != null)
    {
      evaluator.evalAsFunction(script);
    }

    return script;
  }
}
