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.Iterator;
022import java.util.Map;
023
024import lucee.commons.lang.CFTypes;
025import lucee.commons.lang.StringUtil;
026import lucee.runtime.Component;
027import lucee.runtime.ComponentImpl;
028import lucee.runtime.PageContext;
029import lucee.runtime.component.Property;
030import lucee.runtime.exp.PageException;
031import lucee.runtime.op.Caster;
032import lucee.runtime.orm.ORMUtil;
033import lucee.runtime.type.Collection.Key;
034import lucee.runtime.type.util.CollectionUtil;
035import lucee.runtime.type.util.KeyConstants;
036import lucee.runtime.type.util.PropertyFactory;
037import lucee.runtime.type.util.UDFUtil;
038
039public final class UDFHasProperty extends UDFGSProperty {
040
041        private final Property prop;
042        //private ComponentScope scope;
043        
044        private final Key propName;
045        
046        //private static final String NULL="sdsdsdfsfsfjkln fsdfsa";
047
048        public UDFHasProperty(ComponentImpl component,Property prop)  {
049                super(component,"has"+StringUtil.ucFirst(PropertyFactory.getSingularName(prop)),getFunctionArgument(prop),CFTypes.TYPE_BOOLEAN,"wddx");
050                this.prop=prop;
051                this.propName=KeyImpl.getInstance(prop.getName());
052        } 
053
054        private static FunctionArgument[] getFunctionArgument(Property prop) {
055                String t = PropertyFactory.getType(prop);
056                
057                if("struct".equalsIgnoreCase(t)){
058                        FunctionArgument key = new FunctionArgumentImpl(KeyConstants._key,"string",CFTypes.TYPE_STRING,false);
059                        return new FunctionArgument[]{key};
060                }
061                FunctionArgument value = new FunctionArgumentImpl(KeyImpl.init(PropertyFactory.getSingularName(prop)),"any",CFTypes.TYPE_ANY,false);
062                return new FunctionArgument[]{value};
063        }
064        
065        private boolean isStruct() {
066                String t = PropertyFactory.getType(prop);
067                return "struct".equalsIgnoreCase(t);
068        }
069 
070        @Override
071        public UDF duplicate() {
072                return new UDFHasProperty(component,prop);
073        }
074        
075        @Override
076        public Object call(PageContext pageContext, Object[] args,boolean doIncludePath) throws PageException {
077                if(args.length<1) return has(pageContext);
078                return has(pageContext, args[0]);
079        }
080
081        @Override
082        public Object callWithNamedValues(PageContext pageContext, Struct values,boolean doIncludePath) throws PageException {
083                UDFUtil.argumentCollection(values,getFunctionArguments());
084                Key key = arguments[0].getName();
085                Object value = values.get(key,null);
086                if(value==null){
087                        Key[] keys = CollectionUtil.keys(values);
088                        if(keys.length>0) {
089                                value=values.get(keys[0]);
090                        }
091                        else return has(pageContext);
092                }
093                
094                return has(pageContext, value);
095        }
096        
097        private boolean has(PageContext pageContext) {
098                Object propValue = component.getComponentScope().get(propName,null);
099                
100                // struct
101                if(isStruct()) {
102                        if(propValue instanceof Map) {
103                                return !((Map)propValue).isEmpty();
104                        }
105                        return false;
106                }
107                
108                        //Object o;
109                        if(propValue instanceof Array) {
110                                Array arr = ((Array)propValue);
111                                return arr.size()>0;
112                        }
113                        else if(propValue instanceof java.util.List) {
114                                
115                                return ((java.util.List)propValue).size()>0;
116                        }
117                        return propValue instanceof Component;
118                
119        }
120        
121        private boolean has(PageContext pageContext, Object value) throws PageException {
122                Object propValue = component.getComponentScope().get(propName,null);
123                
124                // struct
125                if(isStruct()) {
126                        String strKey = Caster.toString(value);
127                        //if(strKey==NULL) throw new ;
128                        
129                        if(propValue instanceof Struct) {
130                                return ((Struct)propValue).containsKey(KeyImpl.getInstance(strKey));
131                        }
132                        else if(propValue instanceof Map) {
133                                return ((Map)propValue).containsKey(strKey);
134                        }
135                        return false;
136                }
137                
138                        Object o;
139                        
140                        if(propValue instanceof Array) {
141                                Array arr = ((Array)propValue);
142                                Iterator<Object> it = arr.valueIterator();
143                                while(it.hasNext()){
144                                        if(ORMUtil.equals(value,it.next()))return true;
145                                }
146                        }
147                        else if(propValue instanceof java.util.List) {
148                                Iterator it=((java.util.List)propValue).iterator();
149                                while(it.hasNext()){
150                                        o = it.next();
151                                        if(ORMUtil.equals(value,o))return true;
152                                }
153                        }
154                        return false;
155                
156        }
157
158        @Override
159        public Object implementation(PageContext pageContext) throws Throwable {
160                return null;
161        }
162        
163        @Override
164        public Object getDefaultValue(PageContext pc, int index) throws PageException {
165                return prop.getDefault();
166        }
167        
168        @Override
169        public Object getDefaultValue(PageContext pc, int index, Object defaultValue) throws PageException {
170                return prop.getDefault();
171        }
172
173        @Override
174        public String getReturnTypeAsString() {
175                return "boolean";
176        }
177}