package org.chenyang.http.impl.execchain;

import org.chenyang.commons.logging.Log;
import org.chenyang.commons.logging.LogFactory;
import org.chenyang.http.Header;
import org.chenyang.http.HttpException;
import org.chenyang.http.annotation.Contract;
import org.chenyang.http.annotation.ThreadingBehavior;
import org.chenyang.http.client.ServiceUnavailableRetryStrategy;
import org.chenyang.http.client.methods.CloseableHttpResponse;
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.routing.HttpRoute;
import org.chenyang.http.util.Args;
import java.io.IOException;
import java.io.InterruptedIOException;

@Contract(
   threading = ThreadingBehavior.IMMUTABLE_CONDITIONAL
)
public class ServiceUnavailableRetryExec implements ClientExecChain {
   private final Log log = LogFactory.getLog(this.getClass());
   private final ClientExecChain requestExecutor;
   private final ServiceUnavailableRetryStrategy retryStrategy;

   public ServiceUnavailableRetryExec(ClientExecChain requestExecutor, ServiceUnavailableRetryStrategy retryStrategy) {
      Args.notNull(requestExecutor, "HTTP request executor");
      Args.notNull(retryStrategy, "Retry strategy");
      this.requestExecutor = requestExecutor;
      this.retryStrategy = retryStrategy;
   }

   public CloseableHttpResponse execute(HttpRoute route, HttpRequestWrapper request, HttpClientContext context, HttpExecutionAware execAware) throws IOException, HttpException {
      Header[] origheaders = request.getAllHeaders();
      int c = 1;

      while(true) {
         CloseableHttpResponse response = this.requestExecutor.execute(route, request, context, execAware);

         try {
            if (!this.retryStrategy.retryRequest(response, c, context) || !RequestEntityProxy.isRepeatable(request)) {
               return response;
            }

            response.close();
            long nextInterval = this.retryStrategy.getRetryInterval();
            if (nextInterval > 0L) {
               try {
                  this.log.trace("Wait for " + nextInterval);
                  Thread.sleep(nextInterval);
               } catch (InterruptedException var11) {
                  Thread.currentThread().interrupt();
                  throw new InterruptedIOException();
               }
            }

            request.setHeaders(origheaders);
         } catch (RuntimeException ex) {
            response.close();
            throw ex;
         }

         ++c;
      }
   }
}
