package uk.co.todddavies.website;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import com.google.common.collect.ImmutableMap;
import com.google.inject.AbstractModule;
import com.google.inject.BindingAnnotation;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import com.google.inject.servlet.ServletModule;

import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

final class RedirectModule  extends ServletModule {
  
  // TODO: Read from config
  private static final ImmutableMap<String, String> REDIRECT_MAP = ImmutableMap.of(
      "/home/", "/#home",
      "/notes/", "/#notes",
      "/contact/", "/#contact");
  
  private RedirectModule() {}
  
  static AbstractModule create() {
    return new AbstractModule() {
      @Override
      protected void configure() {
        install(new RedirectModule());
        bind(new TypeLiteral<ImmutableMap<String, String>>() {}).annotatedWith(RedirectMap.class)
            .toInstance(REDIRECT_MAP);
      }
    };
  }
  
  @Override
  protected void configureServlets() {
    for (String key : REDIRECT_MAP.keySet()) {
      serve(key).with(RedirectServlet.class);
    }
  }
  
  @Singleton
  @SuppressWarnings("serial")
  private static final class RedirectServlet extends HttpServlet { 
  
    private final ImmutableMap<String, String> redirectMap;
    
    @Inject
    private RedirectServlet(@RedirectMap ImmutableMap<String, String> redirectMap) {
      this.redirectMap = redirectMap;
    }
    
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws IOException {
      String path = req.getRequestURI();
      if (redirectMap.containsKey(path)) {
        resp.sendRedirect(redirectMap.get(path));
      } else {
        resp.sendError(404);
      }
    }
  }
  
  @BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME)
  private @interface RedirectMap {}
}
@@ -646,16 +646,109 @@
 .Target;
+%0Aimport java.util.Map.Entry;%0Aimport java.util.logging.Level;%0Aimport java.util.logging.Logger;
 %0A%0Aimport
@@ -929,16 +929,105 @@
 le %7B%0A  %0A
+  private static final Logger log = Logger.getLogger(RedirectModule.class.getName());%0A  %0A
   // TOD
@@ -1142,17 +1142,16 @@
   %22/home
-/
 %22, %22/#ho
@@ -1168,17 +1168,16 @@
  %22/notes
-/
 %22, %22/#no
@@ -1197,17 +1197,16 @@
 /contact
-/
 %22, %22/#co
@@ -1213,24 +1213,243 @@
 ntact%22);%0A  %0A
+  private static final ImmutableMap%3CString, String%3E GENERATED_MAP =%0A      ImmutableMap.%3CString, String%3Ebuilder()%0A          .putAll(REDIRECT_MAP)%0A          .putAll(addSlashesToPaths(REDIRECT_MAP))%0A          .build();%0A  %0A
   private Re
@@ -1750,24 +1750,25 @@
 nstance(
-REDIRECT
+GENERATED
 _MAP);%0A 
@@ -1861,24 +1861,25 @@
 g key : 
-REDIRECT
+GENERATED
 _MAP.key
@@ -2547,42 +2547,781 @@
     
-resp.sendError(404);%0A      %7D%0A    %7D
+log.log(Level.WARNING, String.format(%22Request to path '%25s' was handled by the redirect %22%0A            + %22module, but was not registered with a redirect target. Registered targets are:%5Cn%25s%22,%0A            path, REDIRECT_MAP.toString()));%0A        resp.sendError(404);%0A      %7D%0A    %7D%0A  %7D%0A  %0A  /**%0A   * Adds slashes to the paths (keys) of a redirect mapping.%0A   * %0A   * E.g. (/contact, /#contact) will go to (/contact/, #contact);%0A   */%0A  private static final ImmutableMap%3CString, String%3E addSlashesToPaths(%0A      ImmutableMap%3CString, String%3E input) %7B%0A    ImmutableMap.Builder%3CString, String%3E output = ImmutableMap.builder();%0A    for (Entry%3CString, String%3E mapping : input.entrySet()) %7B%0A      output.put(mapping.getKey() + '/', mapping.getValue());%0A    %7D%0A    return output.build();
 %0A  %7D

Add paths without slashes to the redirect map as per Issue #8