001package fr.aumgn.bukkitutils.glob;
002
003import java.util.Locale;
004
005import com.google.common.base.Function;
006
007import fr.aumgn.bukkitutils.glob.patterns.GenericGlobPattern;
008import fr.aumgn.bukkitutils.glob.patterns.StringCIGlobPattern;
009import fr.aumgn.bukkitutils.glob.patterns.StringGlobPattern;
010import fr.aumgn.bukkitutils.glob.patterns.WildcardGlobPattern;
011
012/**
013 * GlobPattern builder class.
014 */
015public class Glob {
016
017    private static class CaseInsensitiveToString<T>
018            implements Function<T, String> {
019
020        private final Function<T, String> toString;
021
022        public CaseInsensitiveToString(Function<T, String> toString) {
023            this.toString = toString;
024        }
025
026        @Override
027        public String apply(T obj) {
028            return toString.apply(obj).toLowerCase(Locale.ENGLISH);
029        }
030    }
031
032    private final String rawPattern;
033    private boolean partialStart;
034    private boolean partialEnd;
035    private boolean caseInsensitive;
036
037    public Glob(String pattern) {
038        this.rawPattern = pattern;
039        this.partialStart = false;
040        this.partialEnd = false;
041        this.caseInsensitive = false;
042    }
043
044    /**
045     * Defines that the glob  match the entire token.
046     * Default.
047     */
048    public Glob exact() {
049        this.partialStart = false;
050        this.partialEnd = false;
051        return this;
052    }
053
054    /**
055     * Defines that the glob match the token
056     * from the start.
057     */
058    public Glob fromStart() {
059        this.partialEnd = true;
060        return this;
061    }
062
063    /**
064     * Defines that the glob match the token partially.
065     */
066    public Glob partial() {
067        this.partialStart = true;
068        this.partialEnd = true;
069        return this;
070    }
071
072    /**
073     * Defines that the glob is case sensitive.
074     * Default.
075     */
076    public Glob caseSensitive() {
077        caseInsensitive = false;
078        return this;
079    }
080
081    /**
082     * Alias for {@link #caseSensitive()}.
083     */
084    public Glob cs() {
085        return caseSensitive();
086    }
087
088    /**
089     * Defines that the glob is case insensitive.
090     */
091    public Glob caseInsensitive() {
092        caseInsensitive = true;
093        return this;
094    }
095
096    /**
097     * Alias for {@link #caseInsensitive()}.
098     */
099    public Glob ci() {
100        return caseInsensitive();
101    }
102
103    private String getPattern() {
104        String pattern = rawPattern;
105
106        if (partialStart && pattern.charAt(0) != '*') {
107            pattern = "*" + pattern;
108        }
109
110        if (partialEnd && pattern.charAt(pattern.length() - 1) != '*') {
111            pattern = pattern + "*";
112        }
113
114        if (caseInsensitive) {
115            pattern = pattern.toLowerCase(Locale.ENGLISH);
116        }
117        return pattern;
118    }
119
120    /**
121     * Construct the {@link GlobPattern}.
122     */
123    public GlobPattern<String> build() {
124        if (rawPattern == "*") {
125            return new WildcardGlobPattern<String>();
126        }
127
128        if (caseInsensitive) {
129            return new StringCIGlobPattern(getPattern());
130        } else {
131            return new StringGlobPattern(getPattern());
132        }
133    }
134
135    /**
136     * Construct the {@link GlobPattern}.
137     */
138    public <T> GlobPattern<T> build(Function<T, String> toString) {
139        if (rawPattern == "*") {
140            return new WildcardGlobPattern<T>();
141        }
142
143        Function<T, String> caseAwareToString = toString; 
144        if (caseInsensitive) {
145            caseAwareToString = new CaseInsensitiveToString<T>(toString);
146        }
147
148        return new GenericGlobPattern<T>(getPattern(), caseAwareToString);
149    }
150}