package com.xjeffrose.xio.server;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class Route {

  private static final Pattern keywordPattern = Pattern.compile("(:\\w+|:\\*\\w+)");
  private final String path;
  private final Pattern pathPattern;
  private final List<String> keywords;

  private Route(String path, Pattern pathPattern, List<String> keywords) {
    this.path = path;
    this.pathPattern = pathPattern;
    this.keywords = keywords;
  }

  public static Pattern compile(String pattern, List<String> keywords) {
    StringBuilder regexPattern = new StringBuilder();

    if (pattern.equals("/")) {
      regexPattern.append("/");
    } else {
      final String[] segments = pattern.split("/");

      for (String segment : segments) {
        if (!segment.equals("")) {
          regexPattern.append("/");
          if (keywordPattern.matcher(segment).matches()) {
            String keyword = segment.substring(1);

            if (keyword.indexOf("*") == 0) {
              keyword = keyword.substring(1);
              regexPattern
                .append("(?<")
                .append(keyword)
                .append(">.*)");
            } else {
              regexPattern
                .append("(?<")
                .append(keyword)
                .append(">[^/]*)");
            }
            keywords.add(keyword);
          } else {
            regexPattern.append(segment);
          }
        }
      }
    }
    regexPattern.append("[/]?");

    return Pattern.compile(regexPattern.toString());
  }

  public static Route build(String pattern) {
    List<String> keywords = new ArrayList<>();
    return new Route(pattern, compile(pattern, keywords), keywords);
  }

  public Pattern pathPattern() {
    return pathPattern;
  }

  public boolean matches(String path) {
    return pathPattern.matcher(path).matches();
  }

  public Map<String, String> groups(String path) {
    Matcher matcher = pathPattern.matcher(path);
    if (matcher.matches()) {
      Map<String, String> groups = new HashMap<>();
      for (String keyword : keywords) {
        groups.put(keyword, matcher.group(keyword));
      }
      return groups;
    } else {
      return null;
    }
  }

  // Let's just assume that if two Route objects have been built
  // from the same path that they will have the same pattern and
  // keywords.

  @Override
  public boolean equals(final Object o) {
    if (o == this) return true;
    if (!(o instanceof Route)) return false;
    final Route other = (Route) o;
    return other.path.equals(path);
  }

  @Override
  public int hashCode() {
    return path.hashCode();
  }
}

@@ -2120,39 +2120,8 @@
 h);%0A
-    if (matcher.matches()) %7B%0A  
     
@@ -2162,24 +2162,53 @@
 ashMap%3C%3E();%0A
+    if (matcher.matches()) %7B%0A
       for (S
@@ -2294,24 +2294,28 @@
 ;%0A      %7D%0A  
+  %7D%0A
     return g
@@ -2325,46 +2325,8 @@
 ps;%0A
-    %7D else %7B%0A      return null;%0A    %7D%0A
   %7D%0A

Return an empty Map instead of null