001    package railo.runtime.type;
002    
003    import java.util.HashMap;
004    import java.util.Map;
005    
006    import railo.commons.lang.CFTypes;
007    import railo.commons.lang.StringUtil;
008    import railo.runtime.ComponentImpl;
009    import railo.runtime.PageContext;
010    import railo.runtime.component.Property;
011    import railo.runtime.exp.ExpressionException;
012    import railo.runtime.exp.PageException;
013    import railo.runtime.type.Collection.Key;
014    import railo.runtime.type.util.PropertyFactory;
015    
016    public final class UDFAddProperty extends UDFGSProperty {
017    
018            private final Property prop;
019            //private ComponentScope scope;
020            
021            private final Key propName;
022            
023            private static final Object NULL=new Object();
024    
025            public UDFAddProperty(ComponentImpl component,Property prop)  {
026                    super(component,"add"+StringUtil.ucFirst(PropertyFactory.getSingularName(prop)),getFunctionArgument(prop),CFTypes.TYPE_ANY,"wddx");
027                    this.prop=prop;
028                    this.propName=KeyImpl.getInstance(prop.getName());
029            } 
030    
031            private static FunctionArgument[] getFunctionArgument(Property prop) {
032                    String t = PropertyFactory.getType(prop);
033                    FunctionArgument value = new FunctionArgumentImpl(KeyImpl.init(PropertyFactory.getSingularName(prop)),"any",CFTypes.TYPE_ANY,true);
034                    if("struct".equalsIgnoreCase(t)){
035                            FunctionArgument key = new FunctionArgumentImpl(KeyImpl.KEY,"string",CFTypes.TYPE_STRING,true);
036                            return new FunctionArgument[]{key,value};
037                    }
038                    return new FunctionArgument[]{value};
039            }
040    
041            /**
042             * @see railo.runtime.type.UDF#duplicate()
043             */
044            public UDF duplicate(ComponentImpl c) {
045                    return new UDFAddProperty(c,prop);
046            }
047            
048     
049            public UDF duplicate() {
050                    return duplicate(component);
051            }
052            
053            /**
054             * @see railo.runtime.type.UDF#call(railo.runtime.PageContext, java.lang.Object[], boolean)
055             */
056            public Object call(PageContext pageContext, Object[] args,boolean doIncludePath) throws PageException {
057                    // struct
058                    if(this.arguments.length==2) {
059                            if(args.length<2)
060                                    throw new ExpressionException("The function "+getFunctionName()+" need 2 arguments, only "+args.length+" argment"+(args.length==1?" is":"s are")+" passed in.");
061                            return _call(pageContext, args[0], args[1]);
062                    }
063                    // array
064                    else if(this.arguments.length==1) {
065                            if(args.length<1)
066                                    throw new ExpressionException("The parameter "+this.arguments[0].getName()+" to function "+getFunctionName()+" is required but was not passed in.");
067                            return _call(pageContext, null, args[0]);
068                    }
069                    
070                    // never reached
071                    return component;
072                    
073            }
074    
075            /**
076             * @see railo.runtime.type.UDF#callWithNamedValues(railo.runtime.PageContext, railo.runtime.type.Struct, boolean)
077             */
078            public Object callWithNamedValues(PageContext pageContext, Struct values,boolean doIncludePath) throws PageException {
079                    UDFImpl.argumentCollection(values,getFunctionArguments());
080                    
081                    
082                    // struct
083                    if(this.arguments.length==2) {
084                            Key keyName = arguments[0].getName();
085                            Key valueName = arguments[1].getName();
086                            Object key = values.get(keyName,null);
087                            Object value = values.get(valueName,null);
088                            if(key==null)
089                                    throw new ExpressionException("The parameter "+keyName+" to function "+getFunctionName()+" is required but was not passed in.");
090                            if(value==null)
091                                    throw new ExpressionException("The parameter "+valueName+" to function "+getFunctionName()+" is required but was not passed in.");
092                            
093                            return _call(pageContext, key, value);
094                    }
095                    // array
096                    else if(this.arguments.length==1) {
097                            Key valueName = arguments[0].getName();
098                            Object value = values.get(valueName,null);
099                            if(value==null){
100                                    Key[] keys = values.keys();
101                                    if(keys.length==1) {
102                                            value=values.get(keys[0]);
103                                    }
104                                    else throw new ExpressionException("The parameter "+valueName+" to function "+getFunctionName()+" is required but was not passed in.");
105                            }
106                            return _call(pageContext, null, value);
107                    }
108    
109                    // never reached
110                    return component;
111            }
112            
113            
114            private Object _call(PageContext pageContext, Object key, Object value) throws PageException {
115                    
116                    
117                    Object propValue = component.getComponentScope().get(propName,null);
118                    
119                    // struct
120                    if(this.arguments.length==2) {
121                            key=cast(arguments[0],key,1);
122                            value=cast(arguments[1],value,2);
123                            if(propValue==null){
124                                    HashMap map=new HashMap();
125                                    component.getComponentScope().setEL(propName,map);
126                                    propValue=map;
127                            }       
128                            if(propValue instanceof Struct) {
129                                    ((Struct)propValue).set(KeyImpl.toKey(key), value);
130                            }
131                            else if(propValue instanceof Map) {
132                                    ((Map)propValue).put(key, value);
133                            }
134                    }
135                    else {
136                            value=cast(arguments[0],value,1);
137                            if(propValue==null){
138                                    Array arr=new ArrayImpl();
139                                    component.getComponentScope().setEL(propName,arr);
140                                    propValue=arr;
141                            }       
142                            if(propValue instanceof Array) {
143                                    ((Array)propValue).appendEL(value);
144                            }
145                            else if(propValue instanceof java.util.List) {
146                                    ((java.util.List)propValue).add(value);
147                            }
148                    }
149                    return component;
150            }
151    
152            /**
153             * @see railo.runtime.type.UDF#implementation(railo.runtime.PageContext)
154             */
155            public Object implementation(PageContext pageContext) throws Throwable {
156                    return null;
157            }
158            
159            /**
160             * @see railo.runtime.type.UDF#getDefaultValue(railo.runtime.PageContext, int)
161             */
162            public Object getDefaultValue(PageContext pc, int index) throws PageException {
163                    return prop.getDefault();
164            }
165    
166            /**
167             * @see railo.runtime.type.UDF#getReturnTypeAsString()
168             */
169            public String getReturnTypeAsString() {
170                    return "any";
171            }
172    }