package org.ambraproject.wombat.controller;

import freemarker.core.Environment;
import freemarker.ext.beans.BeanModel;
import freemarker.ext.servlet.HttpRequestHashModel;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
import org.ambraproject.wombat.config.site.Site;
import org.ambraproject.wombat.config.site.SiteSet;
import org.ambraproject.wombat.config.site.UnresolvedSiteException;
import org.ambraproject.wombat.util.HttpDebug;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;

public class SiteResolver implements HandlerMethodArgumentResolver {
  private static final Logger log = LoggerFactory.getLogger(SiteResolver.class);

  @Autowired
  private SiteSet siteSet;

  @Override
  public boolean supportsParameter(MethodParameter parameter) {
    return parameter.getParameterAnnotation(SiteParam.class) != null;
  }

  @Override
  public Site resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                              NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
    HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
    if (request == null) {
      throw new RuntimeException("Could not get an HttpServletRequest object");
    }
    if (log.isDebugEnabled()) {
      log.debug(HttpDebug.dump(request));
    }
    Site site = resolveSite(request);
    if (site == null) {
      throw new UnresolvedSiteException(request);
    }
    mavContainer.addAttribute("site", site);
    return site;
  }

  public Site resolveSite(HttpServletRequest request) {
    Site resolution = null;
    for (Site site : siteSet.getSites()) {
      if (site.getRequestScheme().isForSite(request)) {
        if (resolution != null) {
          String message = String.format("Multiple sites (%s, %s) matched for request: %s",
              resolution, site, HttpDebug.dump(request));
          throw new RuntimeException(message);
        }
        resolution = site;
      }
    }
    return resolution;
  }

  private static HttpServletRequest extractRequest(Environment environment) throws TemplateModelException {
    return ((HttpRequestHashModel) environment.getDataModel().get("Request")).getRequest();
  }

  public Site getSite(Environment environment) throws TemplateModelException {
    TemplateModel site = environment.getDataModel().get("site");
    if (site instanceof BeanModel) {
      Object wrappedObject = ((BeanModel) site).getWrappedObject();
      if (wrappedObject instanceof Site) {
        return (Site) wrappedObject;
      }
    }
    return resolveSite(extractRequest(environment));
  }

  /**
   * Convenience method for {@link org.ambraproject.wombat.config.site.url.SiteRequestScheme#buildLink}.
   */
  public String buildLink(Environment environment, String path) throws TemplateModelException {
    return getSite(environment).getRequestScheme().buildLink(extractRequest(environment), path);
  }

}

@@ -968,16 +968,290 @@
 quest;%0A%0A
+/**%0A * Bean that resolves requests to the sites that the application hosts.%0A * %3Cp/%3E%0A * The sites themselves, and the definitions of how to resolve requests to individual sites, are encapsulated in the%0A * %7B@link SiteSet%7D bean. This object exposes them to the view layer.%0A */%0A
 public c
@@ -1434,16 +1434,142 @@
 teSet;%0A%0A
+  /**%0A   * Apply to every controller parameter annotated with %7B@code @SiteParam%7D, which should be of type %7B@link Site%7D.%0A   */%0A
   @Overr
@@ -1711,16 +1711,148 @@
 l;%0A  %7D%0A%0A
+  /**%0A   * Resolve the site from the request and store it in the model as %7B@code %22site%22%7D.%0A   *%0A   * @see %7B@link #resolveSite%7D%0A   */%0A
   @Overr
@@ -2507,24 +2507,451 @@
  site;%0A  %7D%0A%0A
+  /**%0A   * Determine which site a request is for. Applies the %7B@link org.ambraproject.wombat.config.site.url.SiteRequestScheme%7Ds%0A   * defined in the %7B@link SiteSet%7D bean. Returns %7B@code null%7D if no site is matched.%0A   *%0A   * @param request a request from the web%0A   * @return the site for the request, or %7B@code null%7D%0A   * @throws java.lang.RuntimeException if more than one %7B@code SiteRequestScheme%7D matches the request%0A   */%0A
   public Sit
@@ -3636,16 +3636,212 @@
 );%0A  %7D%0A%0A
+  /**%0A   * Determine the site that a page being rendered belongs to.%0A   *%0A   * @param environment the page's FreeMarker environment%0A   * @return the site%0A   * @throws TemplateModelException%0A   */%0A
   public
@@ -4235,24 +4235,24 @@
 %0A  %7D%0A%0A  /**%0A
-
    * Conveni
@@ -4342,16 +4342,87 @@
 ildLink%7D
+ when applied to%0A   * the request from a FreeMarker %7B@link Environment%7D
 .%0A   */%0A

Add Javadoc to SiteResolver.java