/*
   * Accepts a new request from the HTTP server and creates
   * a conventional execution environment for the request.
   * If the application was invoked as a FastCGI server,
   * the first call to FCGIaccept indicates that the application
   * has completed its initialization and is ready to accept
   * a request.  Subsequent calls to FCGI_accept indicate that
   * the application has completed its processing of the
   * current request and is ready to accept a new request.
   * If the application was invoked as a CGI program, the first
   * call to FCGIaccept is essentially a no-op and the second
   * call returns EOF (-1) as does an error. Application should exit.
   *
   * If the application was invoked as a FastCGI server,
   * and this is not the first call to this procedure,
   * FCGIaccept first flushes any buffered output to the HTTP server.
   *
   * On every call, FCGIaccept accepts the new request and
   * reads the FCGI_PARAMS stream into System.props. It also creates
   * streams that understand FastCGI protocol and take input from
   * the HTTP server send output and error output to the HTTP server,
   * and assigns these new streams to System.in, System.out and
   * System.err respectively.
   *
   * For now, we will just return an int to the caller, which is why
   * this method catches, but doen't throw Exceptions.
   *
   */
  public int FCGIaccept() {
    int acceptResult = 0;

    /*
     * If first call, mark it and if fcgi save original system properties,
     * If not first call, and  we are cgi, we should be gone.
     */
    if (!acceptCalled) {
      isFCGI = System.getenv("FCGI_PORT") != null;
      acceptCalled = true;
      if (isFCGI) {
        /*
         * save original system properties (nonrequest)
         * and get a server socket
         */
        startupProps = new Properties(System.getProperties());
        String str = new String(System.getenv("FCGI_PORT"));
        if (str.length() <= 0) {
          return -1;
        }
        int portNum = Integer.parseInt(str);

        try {
          srvSocket = new ServerSocket(portNum);
        } catch (IOException e) {
          if (request != null) {
            request.socket = null;
          }
          srvSocket = null;
          request = null;
          return -1;
        }
      }
    } else {
      if (!isFCGI) {
        return -1;
      }
    }
    /*
     * If we are cgi, just leave everything as is, otherwise set up env
     */
    if (isFCGI) {
      try {
        acceptResult = FCGIAccept();
      } catch (IOException e) {
        return -1;
      }
      if (acceptResult < 0) {
        return -1;
      }

      /*
       * redirect stdin, stdout and stderr to fcgi socket
       */
      System.setIn(new BufferedInputStream(request.inStream, 8192));
      System.setOut(new PrintStream(new BufferedOutputStream(request.outStream, 8192)));
      System.setErr(new PrintStream(new BufferedOutputStream(request.errStream, 512)));
      System.setProperties(request.params);
    }
    return 0;
  }
  /*
   * Accepts a new request from the HTTP server.
   * Finishes the request accepted by the previous call
   * to FCGI_Accept. Sets up the FCGI environment and reads
   * saved and per request environmental varaibles into
   * the request object. (This is redundant on System.props
   * as long as we can handle only one request object.)
   */
  int FCGIAccept() throws IOException {

    boolean isNewConnection;
    boolean errCloseEx = false;
    boolean outCloseEx = false;

    if (request != null) {
      /*
       * Complete the previous request
       */
      System.err.close();
      System.out.close();
      boolean prevRequestfailed =
          (errCloseEx
              || outCloseEx
              || request.inStream.getFCGIError() != 0
              || request.inStream.getException() != null);
      if (prevRequestfailed || !request.keepConnection) {
        request.socket.close();
        request.socket = null;
      }
      if (prevRequestfailed) {
        request = null;
        return -1;
      }
    } else {
      /*
       * Get a Request and initialize some variables
       */
      request = new FCGIRequest();
      request.socket = null;
      request.inStream = null;
    }
    isNewConnection = false;

    /*
     * if connection isnt open accept a new connection (blocking)
     */
    for (; ; ) {
      if (request.socket == null) {
        try {
          request.socket = srvSocket.accept();
        } catch (IOException e) {
          request.socket = null;
          request = null;
          return -1;
        }
        isNewConnection = true;
      }

      /* Try reading from new connection. If the read fails and
       * it was an old connection the web server probably closed it;
       * try making a new connection before giving up
       */
      request.isBeginProcessed = false;
      request.inStream = new FCGIInputStream(request.socket.getInputStream(), 8192, 0, request);
      request.inStream.fill();
      if (request.isBeginProcessed) {
        break;
      }
      request.socket.close();

      request.socket = null;
      if (isNewConnection) {
        return -1;
      }
    }
    /*
     * Set up the objects for the new request
     */
    request.params = new Properties(startupProps);
    switch (request.role) {
      case FCGIGlobalDefs.def_FCGIResponder:
        request.params.put("ROLE", "RESPONDER");
        break;
      case FCGIGlobalDefs.def_FCGIAuthorizer:
        request.params.put("ROLE", "AUTHORIZER");
        break;
      case FCGIGlobalDefs.def_FCGIFilter:
        request.params.put("ROLE", "FILTER");
        break;
      default:
        return -1;
    }
    request.inStream.setReaderType(FCGIGlobalDefs.def_FCGIParams);
    /*
     * read the rest of request parameters
     */
    if (new FCGIMessage(request.inStream).readParams(request.params) < 0) {
      return -1;
    }
    request.inStream.setReaderType(FCGIGlobalDefs.def_FCGIStdin);
    request.outStream =
        new FCGIOutputStream(
            request.socket.getOutputStream(), 8192, FCGIGlobalDefs.def_FCGIStdout, request);
    request.errStream =
        new FCGIOutputStream(
            request.socket.getOutputStream(), 512, FCGIGlobalDefs.def_FCGIStderr, request);
    request.numWriters = 2;
    return 0;
  }