/** @see java.io.OutputStream#flush() */
  @Override
  public void flush() throws IOException {
    if (_out == null || _bOut != null) {
      long length = _wrapper.getContentLength();
      if (length > 0 && length < _wrapper.getMinCompressSize()) doNotCompress(false);
      else doCompress();
    }

    _out.flush();
  }
  /** Instantiates a new compressed stream. */
  public AbstractCompressedStream(
      String encoding, HttpServletRequest request, CompressedResponseWrapper wrapper, String vary)
      throws IOException {
    _encoding = encoding;
    _wrapper = wrapper;
    _response = (HttpServletResponse) wrapper.getResponse();
    _vary = vary;

    if (_wrapper.getMinCompressSize() == 0) doCompress();
  }
  /**
   * Finish.
   *
   * @throws IOException Signals that an I/O exception has occurred.
   */
  public void finish() throws IOException {
    if (!_closed) {
      if (_out == null || _bOut != null) {
        long length = _wrapper.getContentLength();
        if (length > 0 && length < _wrapper.getMinCompressSize()) doNotCompress(false);
        else doCompress();
      }

      if (_compressedOutputStream != null && !_closed) {
        _closed = true;
        _compressedOutputStream.close();
      }
    }
  }
  /**
   * Do not compress.
   *
   * @throws IOException Signals that an I/O exception has occurred.
   */
  public void doNotCompress(boolean sendVary) throws IOException {
    if (_compressedOutputStream != null)
      throw new IllegalStateException("Compressed output stream is already assigned.");
    if (_out == null || _bOut != null) {
      if (sendVary) setHeader("Vary", _vary);
      if (_wrapper.getETag() != null) setHeader("ETag", _wrapper.getETag());

      _doNotCompress = true;

      _out = _response.getOutputStream();
      setContentLength();

      if (_bOut != null) _out.write(_bOut.getBuf(), 0, _bOut.getCount());
      _bOut = null;
    }
  }
  /**
   * Do compress.
   *
   * @throws IOException Signals that an I/O exception has occurred.
   */
  public void doCompress() throws IOException {
    if (_compressedOutputStream == null) {
      if (_response.isCommitted()) throw new IllegalStateException();

      if (_encoding != null) {
        setHeader("Content-Encoding", _encoding);
        if (_response.containsHeader("Content-Encoding")) {
          setHeader("Vary", _vary);
          _out = _compressedOutputStream = createStream();
          if (_out != null) {
            if (_bOut != null) {
              _out.write(_bOut.getBuf(), 0, _bOut.getCount());
              _bOut = null;
            }

            String etag = _wrapper.getETag();
            if (etag != null)
              setHeader("ETag", etag.substring(0, etag.length() - 1) + '-' + _encoding + '"');
            return;
          }
        }
      }

      doNotCompress(true); // Send vary as it could have been compressed if encoding was present
    }
  }
 /* ------------------------------------------------------------ */
 public void setContentLength() {
   if (_doNotCompress) {
     long length = _wrapper.getContentLength();
     if (length >= 0) {
       if (length < Integer.MAX_VALUE) _response.setContentLength((int) length);
       else _response.setHeader("Content-Length", Long.toString(length));
     }
   }
 }
  /** @see java.io.OutputStream#close() */
  @Override
  public void close() throws IOException {
    if (_closed) return;

    if (_wrapper.getRequest().getAttribute("javax.servlet.include.request_uri") != null) flush();
    else {
      if (_bOut != null) {
        long length = _wrapper.getContentLength();
        if (length < 0) {
          length = _bOut.getCount();
          _wrapper.setContentLength(length);
        }
        if (length < _wrapper.getMinCompressSize()) doNotCompress(false);
        else doCompress();
      } else if (_out == null) {
        // No output
        doNotCompress(false);
      }

      if (_compressedOutputStream != null) _compressedOutputStream.close();
      else _out.close();
      _closed = true;
    }
  }
  /**
   * Check out.
   *
   * @param lengthToWrite the length
   * @throws IOException Signals that an I/O exception has occurred.
   */
  private void checkOut(int lengthToWrite) throws IOException {
    if (_closed) throw new IOException("CLOSED");

    if (_out == null) {
      long length = _wrapper.getContentLength();
      if (_response.isCommitted() || (length >= 0 && length < _wrapper.getMinCompressSize()))
        doNotCompress(false);
      else if (lengthToWrite > _wrapper.getMinCompressSize()) doCompress();
      else _out = _bOut = new ByteArrayOutputStream2(_wrapper.getBufferSize());
    } else if (_bOut != null) {
      long length = _wrapper.getContentLength();
      if (_response.isCommitted() || (length >= 0 && length < _wrapper.getMinCompressSize()))
        doNotCompress(false);
      else if (lengthToWrite >= (_bOut.getBuf().length - _bOut.getCount())) doCompress();
    }
  }