package org.plenix.jsp;

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

import org.plenix.jsp.language.*;

/**
* JspServlet
*
* PolyJsp Servlet
*
* @author Ricardo Rocha
* @version 1.0, 2/15/1999
*/


public class JspServlet extends HttpServlet
{
  String stageDirectory;
  String configurationDirectory;
  String defaultLanguage;
  String defaultVersion;

  boolean debugMode;
  boolean bufferOutput;

  private static Hashtable urls = new Hashtable();

  private static HttpServlet servlet;

  public static HttpServlet getServlet()
  {
    return servlet;
  }

  public void init(ServletConfig config)
    throws ServletException, UnavailableException
  {
    super.init(config);

    // Get servlet
    servlet = this;

    // Redirect stderr on demand
    try
    {
      String logFile = getInitParameter("logFile");

      if (logFile != null)
      {
        System.setErr(new PrintStream(new FileOutputStream(logFile)));
        doLog("PolyJsp Servlet Started");
      }
    }
    catch (IOException e) { }

    // Get configuration parameters
    defaultVersion = getStringParameter("defaultVersion", System.getProperty("polyjsp.default.version"));
    defaultLanguage = getStringParameter("defaultLanguage", System.getProperty("polyjsp.default.language"));

    stageDirectory = getStringParameter("stageDirectory", System.getProperty("polyjsp.stage"));
    configurationDirectory = getStringParameter("configurationDirectory", System.getProperty("polyjsp.configuration"));


    // Initialize resource manager
    try
    {
      ResourceManager.setStageDirectory(stageDirectory);
      ResourceManager.setConfigurationDirectory(configurationDirectory);

      ResourceManager.setDefaultVersion(defaultVersion);
      ResourceManager.setDefaultLanguage(defaultLanguage);
    }
    catch (JspException e)
    {
      unavailable(e.getMessage());
    }

    debugMode = getBooleanParameter("debugMode", false);
    bufferOutput = getBooleanParameter("bufferOutput", false);
  }


  public void service(HttpServletRequest request, HttpServletResponse response)
    throws IOException
  {
    response.setContentType("text/html"); // Force html mime type
    response.setHeader("Expires", "Tues, 01 Jan 1980 00:00:00 GMT"); // Prevent caching

    PrintWriter out = response.getWriter();
    BufferedReader in = request.getReader();

    // *** Handle buffered output & debugging mode
    try
    {
      String currentUrl  = HttpUtils.getRequestURL(request).toString();
      File file = (File) urls.get(currentUrl);

      if (file == null)
      {
        file = getScriptFile(request);
        urls.put(currentUrl, file);
      }

      String fileName = file.getCanonicalPath();
      JspScript script = JspScript.getScript(fileName);

      if (script == null)
      {
        script = new JspScript(file);
      }

      script.execute(request, response);
    }
    catch (Exception exception)
    {
      errorPage(exception, out);

      String errorText = exception.getMessage();

      if (errorText == null)
      {
        errorText = exception.getClass().getName();
      }

      doLog(errorText);
    }
    finally
    {
      try
      {
        out.flush();
      }
      catch (Exception e) { }
    }
  }

  private File getScriptFile(HttpServletRequest request)
    throws ServletException
  {
    String path[] = {
      request.getPathTranslated(),
      request.getRealPath(request.getPathInfo()),
      request.getRealPath(request.getRequestURI()),
      request.getRealPath(request.getServletPath()), // JRun
      request.getPathTranslated() + request.getHeader("Referer") // Jigsaw
    };

    for (int i = 0; i < path.length; i++)
    {
      if (path[i] != null)
      {
        File file = new File(path[i]);

        if (file.isFile() && file.canRead())
        {
          return file;
        }
      }
    }

    String requestURL = HttpUtils.getRequestURL(request).toString();

    throw new ServletException(
      requestURL + ":\n\n" +
      "The file corresponding to this URL " +
        "does not exist, is not a regular file or is not readable.\n\n" +
      "Please, check your URL for correctness. " +
      "If you think you received this message in error, " +
        "please report to the web site's administrator."
    );
  }

  public void destroy()
  {
    Enumeration enumeration = JspScript.scripts();

    while (enumeration.hasMoreElements())
    {
      JspScript script = (JspScript) enumeration.nextElement();

      try
      {
        script.unload();
      }
      catch (Exception e) { }
    }
  }

  private void errorPage(Exception exception, PrintWriter out)
  {
    String exceptionName = exception.getClass().getName();
    String exceptionText = exception.getMessage();

    out.println(
        "<HTML>\n" +
        "<HEAD>\n" +
        "  <TITLE>JSP Error. Exception: " + exceptionName +
        "</TITLE>\n" +
        "</HEAD>\n" +
        "<BODY BGCOLOR='#ffffff'>\n" +
        "  <CENTER><H3><FONT COLOR='red'>Error Processing JSP Request</FONT></H3></CENTER>\n" +
        "  <B><PRE>\n" +
        Util.htmlEncode(exception.getMessage()) + "<BR><P>"
    );

    exception.printStackTrace(out);

    out.println(
        "  </PRE></B>\n" +
        "</BODY>\n" +
        "</HTML>\n"
    );
  }

  private void doLog(String text)
  {
    text = (new Date()).toString() + ": " + text;

    this.log(text);
    System.err.println(text);
  }

  private String getStringParameter(String name, String defaultValue)
    throws ServletException
  {
    String value = getInitParameter(name);

    if (value == null)
    {
      return defaultValue;
    }

    return value;
  }

  private boolean getBooleanParameter(String name, boolean defaultValue)
  {
    String value = getInitParameter(name);

    if (value == null)
    {
      return defaultValue;
    }

    return value.equalsIgnoreCase("true");
  }

  private void unavailable(String message)
    throws UnavailableException
  {
    doLog(message);
    throw new UnavailableException(this, message);
  }

  public String getServletInfo()
  {
    return "Serve Java Server Pages";
  }
}
