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