/**
   * Flush the buffer by looping until the {@link Buffer} is empty
   *
   * @param connection the {@link org.glassfish.grizzly.Connection}.
   * @param dstAddress the destination address.
   * @param message
   * @param currentResult the result of the write operation
   * @param timeout operation timeout value value
   * @param timeunit the timeout unit
   * @return The number of bytes written.
   * @throws java.io.IOException
   */
  protected long write0(
      final NIOConnection connection,
      final SocketAddress dstAddress,
      final WritableMessage message,
      final WriteResult<WritableMessage, SocketAddress> currentResult,
      final long timeout,
      final TimeUnit timeunit)
      throws IOException {

    final SelectableChannel channel = connection.getChannel();
    final long writeTimeout = TimeUnit.MILLISECONDS.convert(timeout, timeunit);

    SelectionKey key = null;
    Selector writeSelector = null;
    int attempts = 0;
    int bytesWritten = 0;

    try {
      synchronized (connection) {
        while (message.hasRemaining()) {
          long len = writeNow0(connection, dstAddress, message, currentResult);

          if (len > 0) {
            attempts = 0;
            bytesWritten += len;
          } else {
            attempts++;
            if (writeSelector == null) {
              writeSelector = transport.getTemporarySelectorIO().getSelectorPool().poll();

              if (writeSelector == null) {
                // Continue using the main one.
                continue;
              }
              key = channel.register(writeSelector, SelectionKey.OP_WRITE);
            } else {
              writeSelector.selectedKeys().clear();
            }

            if (writeSelector.select(writeTimeout) == 0) {
              if (attempts > 2) {
                throw new IOException("Client disconnected");
              }
            }
          }
        }
      }
    } finally {
      transport.getTemporarySelectorIO().recycleTemporaryArtifacts(writeSelector, key);
    }

    return bytesWritten;
  }
  /**
   * Method writes the {@link WritableMessage} to the specific address.
   *
   * @param connection the {@link org.glassfish.grizzly.Connection} to write to
   * @param dstAddress the destination address the <tt>message</tt> will be sent to
   * @param message the {@link WritableMessage}, from which the data will be written
   * @param completionHandler {@link org.glassfish.grizzly.CompletionHandler}, which will get
   *     notified, when write will be completed
   */
  public void write(
      Connection<SocketAddress> connection,
      SocketAddress dstAddress,
      WritableMessage message,
      CompletionHandler<WriteResult<WritableMessage, SocketAddress>> completionHandler,
      final org.glassfish.grizzly.asyncqueue.PushBackHandler pushBackHandler,
      long timeout,
      TimeUnit timeunit) {

    if (message == null) {
      failure(new IllegalStateException("Message cannot be null"), completionHandler);
      return;
    }

    if (connection == null || !(connection instanceof NIOConnection)) {
      failure(
          new IllegalStateException("Connection should be NIOConnection and cannot be null"),
          completionHandler);
      return;
    }

    final NIOConnection nioConnection = (NIOConnection) connection;

    final WriteResult<WritableMessage, SocketAddress> writeResult =
        WriteResult.create(connection, message, dstAddress, 0);

    try {
      write0(nioConnection, dstAddress, message, writeResult, timeout, timeunit);

      // Call PushBackHandler after data is written.
      // IMO It has more sense for blocking case
      if (pushBackHandler != null) {
        pushBackHandler.onAccept(connection, message);
      }

      if (completionHandler != null) {
        completionHandler.completed(writeResult);
      }

      message.release();
    } catch (IOException e) {
      failure(e, completionHandler);
    }
  }