001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.rest.path;
020
021import java.util.ArrayList;
022import java.util.List;
023import java.util.regex.Matcher;
024import java.util.regex.Pattern;
025
026import lucee.runtime.type.Struct;
027
028
029public class ExpressionPath extends Path {
030        
031        private Pattern pattern;
032        private List<String> variables;
033
034        public ExpressionPath(Pattern pattern, List<String> variables) {
035                this.pattern=pattern;
036                this.variables=variables;
037        }
038
039        public static Path getInstance(String path) {
040                /*
041                 TODO  handle if a pattern already has defined a group 
042                 */
043                
044                int last=-1,startIndex,endIndex=0,index;
045                String content,variableName,regexPart;
046                StringBuilder regex=new StringBuilder();
047                List<String> variables=new ArrayList<String>();
048                while((startIndex=path.indexOf('{',last))!=-1){
049                        if(last+1<startIndex) {
050                                delimiter(variables,regex,path.substring(last+1,startIndex));
051                        }
052                                
053                        endIndex=path.indexOf('}',startIndex+1);
054                        if(endIndex==-1) return new LiteralPath(path);
055                        
056                        content=path.substring(startIndex+1,endIndex);
057                        index=content.indexOf(':');
058                        if(index!=-1) {
059                                variableName=content.substring(0,index).trim();
060                                regexPart=content.substring(index+1).trim();
061                        }
062                        else {
063                                variableName=content.trim();
064                                regexPart=".+";
065                        }
066                        regex.append('(');
067                        regex.append(regexPart);
068                        regex.append(')');
069                        variables.add(variableName);
070                        //print.e(variableName);
071                        //print.e(regexPart);
072                        last=endIndex;
073                }
074                
075                if(endIndex+1<path.length())
076                        delimiter(variables,regex,path.substring(endIndex+1));
077                
078                //regex.append("(.*)");
079                
080                Pattern pattern=Pattern.compile(regex.toString());
081                //print.e(regex);
082                //print.e(variables);
083                return new ExpressionPath(pattern,variables);
084        }
085        
086
087        private static void delimiter(List<String> variables, StringBuilder regex, String delimiter) {
088                variables.add(null);
089                regex.append('(');
090                /*print.e(delimiter+":"+Pattern.quote(delimiter));
091                StringBuilder sb=new StringBuilder();
092                int len=delimiter.length();
093                char c;
094                for (int i=0; i<len; i++) {
095                        c=delimiter.charAt(i);
096                        switch(c){
097                        case '.': sb.append("\\.");break;
098                        case '?': sb.append("\\?");break;
099                        case '\\': sb.append("\\\\");break;
100                        case '^': sb.append("\\^");break;
101                        case '$': sb.append("\\$");break;
102                        case '+': sb.append("\\+");break;
103                        default: sb.append(c);
104                        break;
105                        }
106                }*/
107                
108                regex.append(Pattern.quote(delimiter));
109                regex.append(')');
110        }
111
112        @Override
113        public boolean match(Struct result,String path) {
114                String var;
115                Matcher m = pattern.matcher(path);
116                boolean hasMatches=m.find();
117                if(!hasMatches) return false;
118                
119                if (hasMatches) {
120                    // Get all groups for this match
121                        int len=m.groupCount();
122                    for (int i=1; i<=len; i++) {
123                        String groupStr = m.group(i);
124                        var = variables.get(i-1);
125                        if(var!=null) result.setEL(var, groupStr.trim());
126                    }
127                }
128                
129                return true;
130        }
131        
132        /*public static void main(String[] args) {
133                Path path = getInstance("{aaa : \\d+}-{b}");
134                print.e("+++++++++++");
135                Map<String,String> res=new HashMap<String, String>();
136                print.e(path.match(res,"1234-cd"));
137                print.e(res);
138        }*/
139        
140
141        
142        public String toString(){
143                return "expression:"+pattern.pattern();
144        }
145}