/*
 * Copyright 2010 Ning, Inc.
 *
 * Ning licenses this file to you under the Apache License, version 2.0
 * (the "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at:
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 */
package com.ning.http.client.providers.netty;

import com.ning.http.client.AsyncHandler;
import com.ning.http.client.AsyncHttpClientConfig;
import com.ning.http.client.Request;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.ssl.SslHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.ConnectException;
import java.net.URI;
import java.nio.channels.ClosedChannelException;
import java.util.concurrent.atomic.AtomicBoolean;


/**
 * Non Blocking connect.
 */
final class NettyConnectListener<T> implements ChannelFutureListener {

    private final AsyncHttpClientConfig config;
    private final NettyResponseFuture<T> future;
    private final HttpRequest nettyRequest;
    private final AtomicBoolean handshakeDone = new AtomicBoolean(false);

    private NettyConnectListener(AsyncHttpClientConfig config,
                                 NettyResponseFuture<T> future,
                                 HttpRequest nettyRequest) {
        this.config = config;
        this.future = future;
        this.nettyRequest = nettyRequest;
    }

    public NettyResponseFuture<T> future() {
        return future;
    }

    public final void operationComplete(ChannelFuture f) throws Exception {
        if (f.isSuccess()) {
            if (!handshakeDone.getAndSet(true) && f.getChannel().getPipeline().get(NettyAsyncHttpProvider.SSL_HANDLER) != null) {
                ((SslHandler) f.getChannel().getPipeline().get(NettyAsyncHttpProvider.SSL_HANDLER)).handshake().addListener(this);
                return;
            }
            f.getChannel().getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(future);
            future.provider().writeRequest(f.getChannel(), config, future, nettyRequest);
        } else {
            if (future.canRetry() && (NettyAsyncHttpProvider.abortOnDisconnectException(f.getCause())
                    || ClosedChannelException.class.isAssignableFrom(f.getCause().getClass())
                    || future.getState() != NettyResponseFuture.STATE.NEW)) {
                
                if (future.provider().remotelyClosed(f.getChannel(), future)) {
                    return;
                }
            }

            ConnectException e = new ConnectException(f.getCause() != null ? f.getCause().getMessage() : future.getURI().toString());
            e.initCause(f.getCause());
            future.abort(e);
        }
    }

    public static class Builder<T> {
        private final Logger log = LoggerFactory.getLogger(Builder.class);
        private final AsyncHttpClientConfig config;
        private final Request request;
        private final AsyncHandler<T> asyncHandler;
        private NettyResponseFuture<T> future;
        private final NettyAsyncHttpProvider provider;
        private final ChannelBuffer buffer;

        public Builder(AsyncHttpClientConfig config, Request request, AsyncHandler<T> asyncHandler,
                       NettyAsyncHttpProvider provider, ChannelBuffer buffer) {

            this.config = config;
            this.request = request;
            this.asyncHandler = asyncHandler;
            this.future = null;
            this.provider = provider;
            this.buffer = buffer;
        }

        public Builder(AsyncHttpClientConfig config, Request request, AsyncHandler<T> asyncHandler,
                       NettyResponseFuture<T> future, NettyAsyncHttpProvider provider, ChannelBuffer buffer) {

            this.config = config;
            this.request = request;
            this.asyncHandler = asyncHandler;
            this.future = future;
            this.provider = provider;
            this.buffer = buffer;
        }

        public NettyConnectListener<T> build(final URI uri) throws IOException {
            HttpRequest nettyRequest = NettyAsyncHttpProvider.buildRequest(config, request, uri, true, buffer);
            if (future == null) {
                future = NettyAsyncHttpProvider.newFuture(uri, request, asyncHandler, nettyRequest, config, provider);
            }
            return new NettyConnectListener<T>(config, future, nettyRequest);
        }
    }
}

@@ -1384,16 +1384,109 @@
 tener %7B%0A
+    private final static Logger logger = LoggerFactory.getLogger(NettyConnectListener.class);
 %0A    pri
@@ -2682,16 +2682,61 @@
  else %7B%0A
+            Throwable cause = f.getCause();%0A%0A
         
@@ -2763,16 +2763,33 @@
 try() &&
+ cause != null &&
  (NettyA
@@ -2832,28 +2832,21 @@
 ception(
-f.getC
+c
 ause
-()
 )%0A      
@@ -2908,28 +2908,21 @@
 bleFrom(
-f.getC
+c
 ause
-()
 .getClas
@@ -3154,32 +3154,90 @@
 %0A            %7D%0A%0A
+            logger.warn(%22Connect exception: %7B%7D%22, cause);%0A%0A
             Conn
@@ -3297,28 +3297,21 @@
  null ? 
-f.getC
+c
 ause
-()
 .getMess
@@ -3363,34 +3363,78 @@
     
-e.initCause(f.getCause());
+if (cause != null) %7B%0A                e.initCause(cause);%0A            %7D
 %0A   
@@ -3517,83 +3517,8 @@
 %3E %7B%0A
-        private final Logger log = LoggerFactory.getLogger(Builder.class);%0A
     

Check for null, refactor a little