package org.chenyang.http.impl.client;

import org.chenyang.http.HttpException;
import org.chenyang.http.HttpHost;
import org.chenyang.http.HttpRequest;
import org.chenyang.http.annotation.Contract;
import org.chenyang.http.annotation.ThreadingBehavior;
import org.chenyang.http.client.ClientProtocolException;
import org.chenyang.http.client.config.RequestConfig;
import org.chenyang.http.client.methods.CloseableHttpResponse;
import org.chenyang.http.client.methods.Configurable;
import org.chenyang.http.client.methods.HttpExecutionAware;
import org.chenyang.http.client.methods.HttpRequestWrapper;
import org.chenyang.http.client.protocol.HttpClientContext;
import org.chenyang.http.conn.ClientConnectionManager;
import org.chenyang.http.conn.ClientConnectionRequest;
import org.chenyang.http.conn.HttpClientConnectionManager;
import org.chenyang.http.conn.ManagedClientConnection;
import org.chenyang.http.conn.routing.HttpRoute;
import org.chenyang.http.conn.scheme.SchemeRegistry;
import org.chenyang.http.impl.DefaultConnectionReuseStrategy;
import org.chenyang.http.impl.execchain.MinimalClientExec;
import org.chenyang.http.params.BasicHttpParams;
import org.chenyang.http.params.HttpParams;
import org.chenyang.http.protocol.BasicHttpContext;
import org.chenyang.http.protocol.HttpContext;
import org.chenyang.http.protocol.HttpRequestExecutor;
import org.chenyang.http.util.Args;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

@Contract(
   threading = ThreadingBehavior.SAFE_CONDITIONAL
)
class MinimalHttpClient extends CloseableHttpClient {
   private final HttpClientConnectionManager connManager;
   private final MinimalClientExec requestExecutor;
   private final HttpParams params;

   public MinimalHttpClient(HttpClientConnectionManager connManager) {
      this.connManager = (HttpClientConnectionManager)Args.notNull(connManager, "HTTP connection manager");
      this.requestExecutor = new MinimalClientExec(new HttpRequestExecutor(), connManager, DefaultConnectionReuseStrategy.INSTANCE, DefaultConnectionKeepAliveStrategy.INSTANCE);
      this.params = new BasicHttpParams();
   }

   protected CloseableHttpResponse doExecute(HttpHost target, HttpRequest request, HttpContext context) throws IOException, ClientProtocolException {
      Args.notNull(target, "Target host");
      Args.notNull(request, "HTTP request");
      HttpExecutionAware execAware = null;
      if (request instanceof HttpExecutionAware) {
         execAware = (HttpExecutionAware)request;
      }

      try {
         HttpRequestWrapper wrapper = HttpRequestWrapper.wrap(request);
         HttpClientContext localcontext = HttpClientContext.adapt((HttpContext)(context != null ? context : new BasicHttpContext()));
         HttpRoute route = new HttpRoute(target);
         RequestConfig config = null;
         if (request instanceof Configurable) {
            config = ((Configurable)request).getConfig();
         }

         if (config != null) {
            localcontext.setRequestConfig(config);
         }

         return this.requestExecutor.execute(route, wrapper, localcontext, execAware);
      } catch (HttpException httpException) {
         throw new ClientProtocolException(httpException);
      }
   }

   public HttpParams getParams() {
      return this.params;
   }

   public void close() {
      this.connManager.shutdown();
   }

   public ClientConnectionManager getConnectionManager() {
      return new ClientConnectionManager() {
         public void shutdown() {
            MinimalHttpClient.this.connManager.shutdown();
         }

         public ClientConnectionRequest requestConnection(HttpRoute route, Object state) {
            throw new UnsupportedOperationException();
         }

         public void releaseConnection(ManagedClientConnection conn, long validDuration, TimeUnit timeUnit) {
            throw new UnsupportedOperationException();
         }

         public SchemeRegistry getSchemeRegistry() {
            throw new UnsupportedOperationException();
         }

         public void closeIdleConnections(long idletime, TimeUnit timeUnit) {
            MinimalHttpClient.this.connManager.closeIdleConnections(idletime, timeUnit);
         }

         public void closeExpiredConnections() {
            MinimalHttpClient.this.connManager.closeExpiredConnections();
         }
      };
   }
}
