/* ------------------------------------------------------------ */
  public Result generateResponse(
      MetaData.Response info,
      boolean head,
      ByteBuffer header,
      ByteBuffer chunk,
      ByteBuffer content,
      boolean last)
      throws IOException {
    switch (_state) {
      case START:
        {
          if (info == null) return Result.NEED_INFO;

          // Handle 0.9
          if (info.getVersion() == HttpVersion.HTTP_0_9) {
            _persistent = false;
            _endOfContent = EndOfContent.EOF_CONTENT;
            if (BufferUtil.hasContent(content)) _contentPrepared += content.remaining();
            _state = last ? State.COMPLETING : State.COMMITTED;
            return Result.FLUSH;
          }

          // Do we need a response header
          if (header == null) return Result.NEED_HEADER;

          // If we have not been told our persistence, set the default
          if (_persistent == null)
            _persistent = (info.getVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal());

          // prepare the header
          int pos = BufferUtil.flipToFill(header);
          try {
            // generate ResponseLine
            generateResponseLine(info, header);

            // Handle 1xx and no content responses
            int status = info.getStatus();
            if (status >= 100 && status < 200) {
              _noContent = true;

              if (status != HttpStatus.SWITCHING_PROTOCOLS_101) {
                header.put(HttpTokens.CRLF);
                _state = State.COMPLETING_1XX;
                return Result.FLUSH;
              }
            } else if (status == HttpStatus.NO_CONTENT_204
                || status == HttpStatus.NOT_MODIFIED_304) {
              _noContent = true;
            }

            generateHeaders(info, header, content, last);

            // handle the content.
            int len = BufferUtil.length(content);
            if (len > 0) {
              _contentPrepared += len;
              if (isChunking() && !head) prepareChunk(header, len);
            }
            _state = last ? State.COMPLETING : State.COMMITTED;
          } catch (Exception e) {
            String message =
                (e instanceof BufferOverflowException)
                    ? "Response header too large"
                    : e.getMessage();
            throw new IOException(message, e);
          } finally {
            BufferUtil.flipToFlush(header, pos);
          }

          return Result.FLUSH;
        }

      case COMMITTED:
        {
          int len = BufferUtil.length(content);

          // handle the content.
          if (len > 0) {
            if (isChunking()) {
              if (chunk == null) return Result.NEED_CHUNK;
              BufferUtil.clearToFill(chunk);
              prepareChunk(chunk, len);
              BufferUtil.flipToFlush(chunk, 0);
            }
            _contentPrepared += len;
          }

          if (last) {
            _state = State.COMPLETING;
            return len > 0 ? Result.FLUSH : Result.CONTINUE;
          }
          return len > 0 ? Result.FLUSH : Result.DONE;
        }

      case COMPLETING_1XX:
        {
          reset();
          return Result.DONE;
        }

      case COMPLETING:
        {
          if (BufferUtil.hasContent(content)) {
            if (LOG.isDebugEnabled()) LOG.debug("discarding content in COMPLETING");
            BufferUtil.clear(content);
          }

          if (isChunking()) {
            // Do we need a chunk buffer?
            if (chunk == null) return Result.NEED_CHUNK;

            // Write the last chunk
            BufferUtil.clearToFill(chunk);
            prepareChunk(chunk, 0);
            BufferUtil.flipToFlush(chunk, 0);
            _endOfContent = EndOfContent.UNKNOWN_CONTENT;
            return Result.FLUSH;
          }

          _state = State.END;

          return Boolean.TRUE.equals(_persistent) ? Result.DONE : Result.SHUTDOWN_OUT;
        }

      case END:
        if (BufferUtil.hasContent(content)) {
          if (LOG.isDebugEnabled()) LOG.debug("discarding content in COMPLETING");
          BufferUtil.clear(content);
        }
        return Result.DONE;

      default:
        throw new IllegalStateException();
    }
  }
 @Override
 protected void reset() {
   generator.reset();
   super.reset();
 }