1 module hunt.http.routing.impl.AbstractRegexMatcher;
2 
3 import hunt.http.routing.Matcher;
4 import hunt.http.routing.Router;
5 
6 import hunt.collection;
7 import hunt.Exceptions;
8 
9 import hunt.logging;
10 
11 import std.conv;
12 import std.regex;
13 
14 
15 /**
16  * 
17  */
18 abstract class AbstractRegexMatcher : Matcher {
19 
20     protected Map!(RegexRule, Set!Router) _regexMap;
21 
22     protected static class RegexRule {
23         string rule;
24         Regex!char pattern;
25         
26         protected this(string rule) {
27             this.rule = rule;
28             pattern = regex(rule);
29         }
30 
31         override
32         bool opEquals(Object o) {
33             if (this is o) return true;
34             RegexRule regexRule = cast(RegexRule) o;
35             if(regexRule is null) return false;
36             return rule == regexRule.rule;
37         }
38 
39         override
40         size_t toHash() @trusted nothrow {
41             return hashOf(rule);
42         }
43     }
44 
45     protected Map!(RegexRule, Set!(Router)) regexMap() {
46         if (_regexMap is null) {
47             _regexMap = new HashMap!(RegexRule, Set!(Router))();
48         }
49         return _regexMap;
50     }
51 
52     override
53     void add(string rule, Router router) {
54         // regexMap().computeIfAbsent(new RegexRule(rule), k -> new HashSet<>()).add(router);
55         auto r = new RegexRule(rule);
56         if(regexMap().containsKey(r))
57         {
58             regexMap()[r].add(router);
59         }
60         else
61         {
62             auto hs = new HashSet!(Router)();
63             hs.add(router);
64             regexMap().put(r, hs);
65         }
66     }
67 
68     override
69     MatchResult match(string value) {
70         if (_regexMap is null) {
71             return null;
72         }
73 
74         Set!Router routers = new HashSet!Router();
75         Map!(Router, Map!(string, string)) parameters = new HashMap!(Router, Map!(string, string))();
76 
77         foreach(RegexRule rule, Set!Router routerSet; _regexMap)
78         {
79             // tracef("v=%s, pattern=%s", value, rule.rule);
80             RegexMatch!string m = matchAll(value, rule.pattern);
81 
82             if (m.empty) 
83                 continue;
84 
85             routers.addAll(routerSet);
86 
87             Map!(string, string) param = new HashMap!(string, string)();
88             foreach(Captures!string item; m)
89             {
90                 // tracef("front:%s, length:%d", item.front, item.length);
91                 for (size_t i = 1; i <item.length; i++) {
92                     // tracef("%d => %s", i, item[i]);
93                     param.put("group" ~ i.to!string(), item[i]);
94                 }                
95             }
96 
97             if (!param.isEmpty()) {
98                 foreach(router; routerSet)
99                     parameters.put(router, param);
100             }
101         }
102         if (routers.isEmpty()) {
103             return null;
104         } else {
105             return new MatchResult(routers, parameters, getMatchType());
106         }
107     }
108 
109 
110     MatchType getMatchType() { implementationMissing(); return MatchType.PATH; }
111 
112 }