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.type;
020
021import java.util.ArrayList;
022import java.util.Iterator;
023import java.util.List;
024
025import lucee.commons.lang.CFTypes;
026import lucee.commons.lang.ExceptionUtil;
027import lucee.commons.lang.StringUtil;
028import lucee.runtime.Component;
029import lucee.runtime.ComponentImpl;
030import lucee.runtime.PageContext;
031import lucee.runtime.PageSource;
032import lucee.runtime.component.MemberSupport;
033import lucee.runtime.config.Config;
034import lucee.runtime.config.ConfigImpl;
035import lucee.runtime.dump.DumpData;
036import lucee.runtime.dump.DumpProperties;
037import lucee.runtime.dump.DumpTable;
038import lucee.runtime.exp.ApplicationException;
039import lucee.runtime.exp.ExpressionException;
040import lucee.runtime.exp.PageException;
041import lucee.runtime.interpreter.ref.Ref;
042import lucee.runtime.interpreter.ref.cast.Casting;
043import lucee.runtime.interpreter.ref.func.BIFCall;
044import lucee.runtime.interpreter.ref.literal.LFunctionValue;
045import lucee.runtime.interpreter.ref.literal.LString;
046import lucee.runtime.type.Collection.Key;
047import lucee.runtime.type.util.ArrayUtil;
048import lucee.runtime.type.util.CollectionUtil;
049import lucee.runtime.type.util.UDFUtil;
050import lucee.transformer.library.function.FunctionLib;
051import lucee.transformer.library.function.FunctionLibFunction;
052import lucee.transformer.library.function.FunctionLibFunctionArg;
053
054public class BIF extends MemberSupport implements UDFPlus {
055        
056        private final FunctionLibFunction flf;
057        private short rtnType=CFTypes.TYPE_UNKNOW;
058        private ComponentImpl owner;
059        private final ConfigImpl ci;
060        private FunctionArgument[] args;
061
062        public BIF(Config config,String name) throws ApplicationException{
063                super(Component.ACCESS_PUBLIC);
064                ci=(ConfigImpl) config;
065                FunctionLib fl = ci.getCombinedFLDs();
066                flf = fl.getFunction(name);
067                
068                // BIF not fuound
069                if(flf==null) {
070                        Key[] keys = CollectionUtil.toKeys(fl.getFunctions().keySet());
071                        throw new ApplicationException(ExceptionUtil.similarKeyMessage(keys, name, "build in function", "build in functions", false));
072                }
073        }
074        
075        public BIF(Config config, FunctionLibFunction flf) {
076                super(Component.ACCESS_PUBLIC);
077                ci=(ConfigImpl) config;
078                this.flf=flf;
079        }
080
081        @Override
082        public FunctionArgument[] getFunctionArguments() {
083                if(args==null) {
084                        ArrayList<FunctionLibFunctionArg> src = flf.getArg();
085                        args = new FunctionArgument[src.size()];
086                        
087                        String def;
088                        int index=-1;
089                        FunctionLibFunctionArg arg;
090                        Iterator<FunctionLibFunctionArg> it = src.iterator();
091                        while(it.hasNext()){
092                                arg = it.next();
093                                def = arg.getDefaultValue();
094                                args[++index]=new FunctionArgumentImpl(
095                                                KeyImpl.init(arg.getName())
096                                                , arg.getTypeAsString()
097                                                , arg.getType()
098                                                , arg.getRequired()
099                                                , def==null?FunctionArgument.DEFAULT_TYPE_NULL:FunctionArgument.DEFAULT_TYPE_LITERAL
100                                                , true
101                                                , arg.getName()
102                                                , arg.getDescription()
103                                                , null);
104                        }
105                }
106                
107                return args;
108        }
109
110        @Override
111        public Object callWithNamedValues(PageContext pageContext, Struct values, boolean doIncludePath) throws PageException {
112                ArrayList<FunctionLibFunctionArg> flfas = flf.getArg();
113                Iterator<FunctionLibFunctionArg> it = flfas.iterator();
114                FunctionLibFunctionArg arg;
115                Object val;
116
117                List<Ref> refs=new ArrayList<Ref>();
118                while(it.hasNext()){
119                        arg=it.next();
120                        
121                        // match by name
122                        val = values.get(arg.getName(),null);
123                        
124                        //match by alias
125                        if(val==null) {
126                                String alias=arg.getAlias();
127                                if(!StringUtil.isEmpty(alias,true)) {
128                                        String[] aliases = lucee.runtime.type.util.ListUtil.trimItems(lucee.runtime.type.util.ListUtil.listToStringArray(alias,','));
129                                        for(int x=0;x<aliases.length;x++){
130                                                val = values.get(aliases[x],null);
131                                                if(val!=null) break;
132                                        }
133                                }
134                        }
135                        
136                        if(val==null) {
137                                if(arg.getRequired()) {
138                                        String[] names = flf.getMemberNames();
139                                        String n=ArrayUtil.isEmpty(names)?"":names[0];
140                                        throw new ExpressionException("missing required argument ["+arg.getName()+"] for build in function call ["+n+"]");
141                                }
142                        }
143                        else{
144                                refs.add(new Casting(arg.getTypeAsString(),arg.getType(),new LFunctionValue(new LString(arg.getName()),val)));
145                        }
146                }
147                
148                BIFCall call=new BIFCall(flf, refs.toArray(new Ref[refs.size()]));
149                return call.getValue(pageContext);
150        }
151
152
153        @Override
154        public Object call(PageContext pageContext, Object[] args, boolean doIncludePath) throws PageException {
155                ArrayList<FunctionLibFunctionArg> flfas = flf.getArg();
156                FunctionLibFunctionArg flfa;
157                List<Ref> refs=new ArrayList<Ref>();
158                for(int i=0;i<args.length;i++){
159                        if(i>=flfas.size()) throw new ApplicationException("too many Attributes in function call ["+flf.getName()+"]");
160                        flfa=flfas.get(i);
161                        refs.add(new Casting(flfa.getTypeAsString(),flfa.getType(),args[i]));
162                }
163                BIFCall call=new BIFCall(flf, refs.toArray(new Ref[refs.size()]));
164                return call.getValue(pageContext);
165        }
166
167        @Override
168        public Object callWithNamedValues(PageContext pageContext, Key calledName, Struct values, boolean doIncludePath) throws PageException {
169                return callWithNamedValues(pageContext, values, doIncludePath);
170        }
171
172        @Override
173        public Object call(PageContext pageContext, Key calledName, Object[] args, boolean doIncludePath) throws PageException {
174                return call(pageContext, args, doIncludePath);
175        }
176        
177
178
179
180
181
182
183        @Override
184        public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
185                DumpTable dt= (DumpTable) UDFUtil.toDumpData(pageContext, maxlevel, dp,this,UDFUtil.TYPE_BIF);
186                //dt.setTitle(title);
187                return dt;
188        }
189
190        @Override
191        public UDF duplicate() {
192                return new BIF(ci, flf);
193        }
194
195        @Override
196        public Object duplicate(boolean deepCopy) {
197                return duplicate();
198        }
199
200        @Override
201        public Component getOwnerComponent() {
202                return owner;
203        }
204
205        @Override
206        public String getDisplayName() {
207                return flf.getName();
208        }
209
210        @Override
211        public String getHint() {
212                return flf.getDescription();
213        }
214
215        @Override
216        public String getFunctionName() {
217                return flf.getName();
218        }
219
220        @Override
221        public int getReturnType() {
222                if(rtnType==CFTypes.TYPE_UNKNOW)
223                        rtnType=CFTypes.toShort(flf.getReturnTypeAsString(), false, CFTypes.TYPE_UNKNOW);
224                return rtnType;
225        }
226
227        @Override
228        public String getDescription() {
229                return flf.getDescription();
230        }
231
232        @Override
233        public void setOwnerComponent(ComponentImpl owner) {
234                this.owner=owner;
235        }
236
237        @Override
238        public int getReturnFormat(int defaultFormat) {
239                return getReturnFormat();
240        }
241
242        @Override
243        public int getReturnFormat() {
244                return UDF.RETURN_FORMAT_WDDX;
245        }
246
247        @Override
248        public String getReturnTypeAsString() {
249                return flf.getReturnTypeAsString();
250        }
251        
252
253
254        @Override
255        public Object getValue() {
256                return this;
257        }
258        
259        @Override
260        public boolean getOutput() {
261                return false;
262        }
263
264        @Override
265        public Object getDefaultValue(PageContext pc, int index) throws PageException {
266                return null;
267        }
268
269        @Override
270        public Boolean getSecureJson() {
271                return null;
272        }
273
274        @Override
275        public Boolean getVerifyClient() {
276                return null;
277        }
278
279        @Override
280        public PageSource getPageSource() {
281                return null;
282        }
283
284        @Override
285        public int getIndex() {
286                return -1;
287        }
288
289        @Override
290        public Object getDefaultValue(PageContext pc, int index, Object defaultValue) throws PageException {
291                return null;
292        }
293
294        
295        
296        // MUST
297        @Override
298        public Struct getMetaData(PageContext pc) throws PageException {
299                // TODO Auto-generated method stub
300                return new StructImpl();
301        }
302
303        @Override
304        public Object implementation(PageContext pageContext) throws Throwable {
305                // TODO Auto-generated method stub
306                return null;
307        }
308
309
310}