package io.github.azagniotov.matcher;

/**
 * Path matcher implementation for Ant-style path patterns. This implementation matches URLs using the following rules:
 * <p/>
 * '?' - matches one character
 * '*' - matches zero or more characters
 * '**' - matches zero or more directories in a path
 */
public class AntPathMatcher {

    private static final char ASTERISK = '*';
    private static final char QUESTION = '?';
    public static final char PATH_SEPARATOR = '/';

    public boolean isMatch(final String pattern, final String path) {
        if (pattern.isEmpty()) {
            return path.isEmpty();
        } else if (pattern.length() == 1 && pattern.charAt(0) == ASTERISK) {
            return path.isEmpty() || path.charAt(0) != PATH_SEPARATOR && isMatch(pattern, path.substring(1));
        } else if (path.isEmpty() && pattern.charAt(0) == PATH_SEPARATOR) {
            return doubleAsteriskMatch(pattern.substring(1), path);
        }

        final char patternStart = pattern.charAt(0);
        if (patternStart == ASTERISK) {
            if (doubleAsteriskMatch(pattern, path)) {
                return true;
            }

            int start = 0;
            while (start < path.length()) {
                if (isMatch(pattern.substring(1), path.substring(start))) {
                    return true;
                }
                start++;
            }
            return isMatch(pattern.substring(1), path.substring(start));
        }

        return !path.isEmpty() && (path.charAt(0) == patternStart || patternStart == QUESTION)
                && isMatch(pattern.substring(1), path.substring(1));
    }

    private boolean doubleAsteriskMatch(final String pattern, final String path) {
        if (pattern.length() == 1 || pattern.charAt(1) != ASTERISK) {
            return false;
        } else if (pattern.length() == 2 || isMatch(pattern.substring(3), path)) {
            return true;
        }

        int pointer = movePointer(path);
        return (isMatch(pattern.substring(2), path.substring(pointer)) ||
                (pointer < path.length() && doubleAsteriskMatch(pattern, path.substring(pointer + 1))));

    }

    private int movePointer(final String path) {
        int pointer = 0;
        while (pointer < path.length() && (path.charAt(pointer) != PATH_SEPARATOR)) {
            pointer++;
        }
        return pointer;
    }
}

@@ -291,17 +291,389 @@
  path%0A *
-/
+ %3Cp%3E%0A * The instances of this class can be configured via its %7B@link Builder%7D to:%0A * (1) Use a custom path separator. The default is '/' character%0A * (2) Ignore character case during comparison. The default is case-sensitive%0A * %3Cp%3E%0A * The custom path separator & ignoring character case options were inspired by Spring's AntPathMatcher%0A */%0A@SuppressWarnings(%22WeakerAccess%22)
 %0Apublic 
@@ -793,21 +793,22 @@
 ';%0A    p
-ublic
+rivate
  static 
@@ -817,34 +817,280 @@
 nal 
-char PATH_SEPARATOR = '/';
+int ASCII_CASE_DIFFERENCE = 32;%0A%0A    private final char pathSeparator;%0A    private final boolean ignoreCase;%0A%0A    private AntPathMatcher(final char pathSeparator, boolean ignoreCase) %7B%0A        this.pathSeparator = pathSeparator;%0A        this.ignoreCase = ignoreCase;%0A    %7D
 %0A%0A  
@@ -1357,30 +1357,29 @@
 t(0) != 
-PATH_SEPARATOR
+pathSeparator
  && isMa
@@ -1469,30 +1469,29 @@
 t(0) == 
-PATH_SEPARATOR
+pathSeparator
 ) %7B%0A    
@@ -2107,24 +2107,30 @@
 sEmpty() && 
+(equal
 (path.charAt
@@ -2128,27 +2128,25 @@
 th.charAt(0)
- ==
+,
  patternStar
@@ -2146,16 +2146,17 @@
 ernStart
+)
  %7C%7C patt
@@ -2245,32 +2245,438 @@
 ing(1));%0A    %7D%0A%0A
+    private boolean equal(final char pathChar, final char patternChar) %7B%0A        if (ignoreCase) %7B%0A            return pathChar == patternChar %7C%7C%0A                    ((pathChar %3E patternChar) ?%0A                            pathChar == patternChar + ASCII_CASE_DIFFERENCE :%0A                            pathChar == patternChar - ASCII_CASE_DIFFERENCE);%0A        %7D%0A        return pathChar == patternChar;%0A    %7D%0A%0A
     private bool
@@ -2983,26 +2983,128 @@
 r = 
-movePointer(path);
+0;%0A        while (pointer %3C path.length() && (path.charAt(pointer) != pathSeparator)) %7B%0A            pointer++;%0A        %7D
 %0A   
@@ -3296,219 +3296,582 @@
    p
-rivate int movePointer(final String path) %7B%0A        int pointer = 0;%0A        while (pointer %3C path.length() && (path.charAt(pointer) != PATH_SEPARATOR)) %7B%0A            pointer++;%0A        %7D%0A        return pointer;
+ublic static final class Builder %7B%0A%0A        private char pathSeparator = '/';%0A        private boolean ignoreCase = false;%0A%0A        public Builder() %7B%0A%0A        %7D%0A%0A        public Builder withPathSeparator(final char pathSeparator) %7B%0A            this.pathSeparator = pathSeparator;%0A            return this;%0A        %7D%0A%0A        public Builder withIgnoreCase(final boolean ignoreCase) %7B%0A            this.ignoreCase = ignoreCase;%0A            return this;%0A        %7D%0A%0A        public AntPathMatcher build() %7B%0A            return new AntPathMatcher(pathSeparator, ignoreCase);%0A        %7D
 %0A   

Update AntPathMatcher.java