package org.chenyang.http.impl.client;

import org.chenyang.commons.logging.Log;
import org.chenyang.commons.logging.LogFactory;
import org.chenyang.http.Header;
import org.chenyang.http.HttpHost;
import org.chenyang.http.HttpRequest;
import org.chenyang.http.HttpResponse;
import org.chenyang.http.ProtocolException;
import org.chenyang.http.annotation.Contract;
import org.chenyang.http.annotation.ThreadingBehavior;
import org.chenyang.http.client.CircularRedirectException;
import org.chenyang.http.client.RedirectHandler;
import org.chenyang.http.client.utils.URIUtils;
import org.chenyang.http.params.HttpParams;
import org.chenyang.http.protocol.HttpContext;
import org.chenyang.http.util.Args;
import org.chenyang.http.util.Asserts;
import java.net.URI;
import java.net.URISyntaxException;

/** @deprecated */
@Deprecated
@Contract(
   threading = ThreadingBehavior.IMMUTABLE
)
public class DefaultRedirectHandler implements RedirectHandler {
   private final Log log = LogFactory.getLog(this.getClass());
   private static final String REDIRECT_LOCATIONS = "http.protocol.redirect-locations";

   public boolean isRedirectRequested(HttpResponse response, HttpContext context) {
      Args.notNull(response, "HTTP response");
      int statusCode = response.getStatusLine().getStatusCode();
      switch (statusCode) {
         case 301:
         case 302:
         case 307:
            HttpRequest request = (HttpRequest)context.getAttribute("http.request");
            String method = request.getRequestLine().getMethod();
            return method.equalsIgnoreCase("GET") || method.equalsIgnoreCase("HEAD");
         case 303:
            return true;
         case 304:
         case 305:
         case 306:
         default:
            return false;
      }
   }

   public URI getLocationURI(HttpResponse response, HttpContext context) throws ProtocolException {
      Args.notNull(response, "HTTP response");
      Header locationHeader = response.getFirstHeader("location");
      if (locationHeader == null) {
         throw new ProtocolException("Received redirect response " + response.getStatusLine() + " but no location header");
      } else {
         String location = locationHeader.getValue();
         if (this.log.isDebugEnabled()) {
            this.log.debug("Redirect requested to location '" + location + "'");
         }

         URI uri;
         try {
            uri = new URI(location);
         } catch (URISyntaxException ex) {
            throw new ProtocolException("Invalid redirect URI: " + location, ex);
         }

         HttpParams params = response.getParams();
         if (!uri.isAbsolute()) {
            if (params.isParameterTrue("http.protocol.reject-relative-redirect")) {
               throw new ProtocolException("Relative redirect location '" + uri + "' not allowed");
            }

            HttpHost target = (HttpHost)context.getAttribute("http.target_host");
            Asserts.notNull(target, "Target host");
            HttpRequest request = (HttpRequest)context.getAttribute("http.request");

            try {
               URI requestURI = new URI(request.getRequestLine().getUri());
               URI absoluteRequestURI = URIUtils.rewriteURI(requestURI, target, URIUtils.DROP_FRAGMENT_AND_NORMALIZE);
               uri = URIUtils.resolve(absoluteRequestURI, uri);
            } catch (URISyntaxException ex) {
               throw new ProtocolException(ex.getMessage(), ex);
            }
         }

         if (params.isParameterFalse("http.protocol.allow-circular-redirects")) {
            RedirectLocations redirectLocations = (RedirectLocations)context.getAttribute("http.protocol.redirect-locations");
            if (redirectLocations == null) {
               redirectLocations = new RedirectLocations();
               context.setAttribute("http.protocol.redirect-locations", redirectLocations);
            }

            URI redirectURI;
            if (uri.getFragment() != null) {
               try {
                  HttpHost target = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
                  redirectURI = URIUtils.rewriteURI(uri, target, URIUtils.DROP_FRAGMENT_AND_NORMALIZE);
               } catch (URISyntaxException ex) {
                  throw new ProtocolException(ex.getMessage(), ex);
               }
            } else {
               redirectURI = uri;
            }

            if (redirectLocations.contains(redirectURI)) {
               throw new CircularRedirectException("Circular redirect to '" + redirectURI + "'");
            }

            redirectLocations.add(redirectURI);
         }

         return uri;
      }
   }
}
