/* ------------------------------------------------------------ */
  public PrintWriter getWriter() throws java.io.IOException {
    if (_outputState == DISABLED) return __nullServletWriter;

    if (_outputState != NO_OUT && _outputState != WRITER_OUT) throw new IllegalStateException();

    // If we are switching modes, flush output to try avoid overlaps.
    if (_out != null) _out.flush();

    /* if there is no writer yet */
    if (_writer == null) {
      /* get encoding from Content-Type header */
      String encoding = _httpResponse.getCharacterEncoding();

      if (encoding == null) {
        if (_servletHttpRequest != null) {
          /* implementation of educated defaults */
          String mimeType = _httpResponse.getMimeType();
          encoding =
              _servletHttpRequest
                  .getServletHandler()
                  .getHttpContext()
                  .getEncodingByMimeType(mimeType);
        }
        if (encoding == null) encoding = StringUtil.__ISO_8859_1;
        _httpResponse.setCharacterEncoding(encoding, true);
      }

      /* construct Writer using correct encoding */
      _writer = new ServletWriter(_httpResponse.getOutputStream(), encoding);
    }
    _outputState = WRITER_OUT;
    return _writer;
  }
  /**
   * Sets the locale of the response, setting the headers (including the Content-Type's charset) as
   * appropriate. This method should be called before a call to {@link #getWriter}. By default, the
   * response locale is the default locale for the server.
   *
   * @see #getLocale
   * @param locale the Locale of the response
   */
  public void setLocale(Locale locale) {
    if (locale == null || isCommitted()) return;

    _locale = locale;
    setHeader(HttpFields.__ContentLanguage, locale.toString().replace('_', '-'));

    if (this._outputState == 0) {
      /* get current MIME type from Content-Type header */
      String type = _httpResponse.getField(HttpFields.__ContentType);
      if (type == null) {
        // servlet did not set Content-Type yet
        // so lets assume default one
        type = "application/octet-stream";
      }

      HttpContext httpContext = _servletHttpRequest.getServletHandler().getHttpContext();
      if (httpContext instanceof ServletHttpContext) {
        String charset = ((ServletHttpContext) httpContext).getLocaleEncoding(locale);
        if (charset != null && charset.length() > 0) {
          int semi = type.indexOf(';');
          if (semi < 0) type += "; charset=" + charset;
          else if (!_charEncodingSetInContentType)
            type = type.substring(0, semi) + "; charset=" + charset;

          setHeader(HttpFields.__ContentType, type);
        }
      }
    }
  }
  /* ------------------------------------------------------------ */
  public String encodeURL(String url) {
    // should not encode if cookies in evidence
    if (_servletHttpRequest == null
        || _servletHttpRequest.isRequestedSessionIdFromCookie()
            && _servletHttpRequest.getServletHandler().isUsingCookies()) return url;

    // get session;
    if (_session == null && !_noSession) {
      _session = _servletHttpRequest.getSession(false);
      _noSession = (_session == null);
    }

    // no session or no url
    if (_session == null || url == null) return url;

    // invalid session
    String id = _session.getId();
    if (id == null) return url;

    // Check host and port are for this server
    // TODO not implemented

    // Already encoded
    int prefix = url.indexOf(SessionManager.__SessionUrlPrefix);
    if (prefix != -1) {
      int suffix = url.indexOf("?", prefix);
      if (suffix < 0) suffix = url.indexOf("#", prefix);

      if (suffix <= prefix)
        return url.substring(0, prefix + SessionManager.__SessionUrlPrefix.length()) + id;
      return url.substring(0, prefix + SessionManager.__SessionUrlPrefix.length())
          + id
          + url.substring(suffix);
    }

    // edit the session
    int suffix = url.indexOf('?');
    if (suffix < 0) suffix = url.indexOf('#');
    if (suffix < 0) return url + SessionManager.__SessionUrlPrefix + id;
    return url.substring(0, suffix)
        + SessionManager.__SessionUrlPrefix
        + id
        + url.substring(suffix);
  }
  /* ------------------------------------------------------------ */
  public void sendRedirect(String url) throws IOException {
    if (url == null) throw new IllegalArgumentException();

    if (!URI.hasScheme(url)) {
      StringBuffer buf = _servletHttpRequest.getHttpRequest().getRootURL();
      if (url.startsWith("/")) buf.append(URI.canonicalPath(url));
      else {
        String path = _servletHttpRequest.getRequestURI();
        String parent = (path.endsWith("/")) ? path : URI.parentPath(path);
        url = URI.canonicalPath(URI.addPaths(parent, url));
        if (!url.startsWith("/")) buf.append('/');
        buf.append(url);
      }

      url = buf.toString();
    }

    resetBuffer();

    _httpResponse.setField(HttpFields.__Location, url);
    _httpResponse.setStatus(HttpResponse.__302_Moved_Temporarily);
    complete();
  }
  /* ------------------------------------------------------------ */
  public ServletOutputStream getOutputStream() {
    if (_outputState == DISABLED) return __nullServletOut;

    if (_outputState != NO_OUT && _outputState != OUTPUTSTREAM_OUT)
      throw new IllegalStateException();

    if (_writer != null) {
      _writer.flush();
      _writer.disable();
      _writer = null;
    }

    if (_out == null) _out = new ServletOut(_servletHttpRequest.getHttpRequest().getOutputStream());
    _outputState = OUTPUTSTREAM_OUT;
    return _out;
  }
  /* ------------------------------------------------------------ */
  public void sendError(int status, String message) throws IOException {
    // Find  error page.
    String error_page =
        _servletHttpRequest.getServletHandler().getErrorPage(status, _servletHttpRequest);

    resetBuffer();

    // Handle error page?
    if (error_page == null) {
      // handle normally
      _httpResponse.sendError(status, message);
    } else {
      _httpResponse.setStatus(status, message);

      if (message == null) {
        message = (String) HttpResponse.__statusMsg.get(TypeUtil.newInteger(status));
        if (message == null) message = "" + status;
      }

      // handle error page
      ServletHolder holder = _servletHttpRequest.getServletHolder();
      if (holder != null)
        _servletHttpRequest.setAttribute(ServletHandler.__J_S_ERROR_SERVLET_NAME, holder.getName());
      _servletHttpRequest.setAttribute(
          ServletHandler.__J_S_ERROR_REQUEST_URI, _servletHttpRequest.getRequestURI());
      _servletHttpRequest.setAttribute(ServletHandler.__J_S_ERROR_STATUS_CODE, new Integer(status));
      _servletHttpRequest.setAttribute(ServletHandler.__J_S_ERROR_MESSAGE, message);

      RequestDispatcher dispatcher =
          _servletHttpRequest
              .getServletHandler()
              .getServletContext()
              .getRequestDispatcher(error_page);

      try {
        ((Dispatcher) dispatcher).error(_servletHttpRequest, this);
      } catch (ServletException e) {
        log.warn(LogSupport.EXCEPTION, e);
        _httpResponse.sendError(status, message);
      }
    }
    complete();
  }
 /* ------------------------------------------------------------ */
 public ServletHttpResponse(ServletHttpRequest request, HttpResponse response) {
   _servletHttpRequest = request;
   _servletHttpRequest.setServletHttpResponse(this);
   _httpResponse = response;
 }