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.functions.closure;
020
021import java.util.Enumeration;
022import java.util.Iterator;
023import java.util.List;
024import java.util.ListIterator;
025import java.util.Map.Entry;
026
027import lucee.runtime.PageContext;
028import lucee.runtime.exp.CasterException;
029import lucee.runtime.exp.FunctionException;
030import lucee.runtime.exp.PageException;
031import lucee.runtime.functions.BIF;
032import lucee.runtime.op.Caster;
033import lucee.runtime.type.Array;
034import lucee.runtime.type.Collection.Key;
035import lucee.runtime.type.Iteratorable;
036import lucee.runtime.type.Query;
037import lucee.runtime.type.Struct;
038import lucee.runtime.type.UDF;
039import lucee.runtime.type.it.ForEachQueryIterator;
040import lucee.runtime.type.scope.ArgumentIntKey;
041import lucee.runtime.type.util.ListUtil;
042import lucee.runtime.type.util.StringListData;
043
044public class Reduce extends BIF {
045
046        private static final long serialVersionUID = -5940580562772523622L;
047
048        public static Object call(PageContext pc , Object obj, UDF udf) throws PageException {
049                return _call(pc, obj, udf,null);
050        }
051        
052        public static Object call(PageContext pc , Object obj, UDF udf, Object initalValue) throws PageException {
053                return _call(pc, obj, udf,initalValue);
054        }
055        
056        public static Object _call(PageContext pc , Object obj, UDF udf, Object initalValue) throws PageException { 
057                
058                
059                Object value;
060                
061                // Array
062                if(obj instanceof Array) {
063                        value=invoke(pc, (Array)obj, udf,initalValue);
064                }
065                // Query
066                else if(obj instanceof Query) {
067                        value=invoke(pc, (Query)obj, udf,initalValue);
068                }
069                // Struct
070                else if(obj instanceof Struct) {
071                        value=invoke(pc, (Struct)obj, udf,initalValue);
072                }
073                // other Iteratorable
074                else if(obj instanceof Iteratorable) {
075                        value=invoke(pc, (Iteratorable)obj, udf,initalValue);
076                }
077                // Map
078                else if(obj instanceof java.util.Map) {
079                        value=invoke(pc, (java.util.Map)obj, udf,initalValue);
080                }
081                //List
082                else if(obj instanceof List) {
083                        value=invoke(pc, (List)obj, udf,initalValue);
084                }
085                // Iterator
086                else if(obj instanceof Iterator) {
087                        value=invoke(pc, (Iterator)obj, udf,initalValue);
088                }
089                // Enumeration
090                else if(obj instanceof Enumeration) {
091                        value=invoke(pc, (Enumeration)obj, udf,initalValue);
092                }
093                else if(obj instanceof StringListData) {
094                        value=invoke(pc, (StringListData)obj, udf,initalValue);
095                }
096                else
097                        throw new FunctionException(pc, "Filter", 1, "data", "cannot iterate througth this type "+Caster.toTypeName(obj.getClass()));
098                
099                
100                return value;
101        }
102
103        private static Object invoke(PageContext pc, Array arr, UDF udf, Object initalValue) throws CasterException, PageException {
104                Iterator<Entry<Key, Object>> it = arr.entryIterator();
105                Entry<Key, Object> e;
106                while(it.hasNext()){
107                        e = it.next();
108                        initalValue=udf.call(pc, new Object[]{initalValue,e.getValue(),Caster.toDoubleValue(e.getKey().getString()),arr}, true);
109                }
110                return initalValue;
111        }
112
113        private static Object invoke(PageContext pc, StringListData sld, UDF udf, Object initalValue) throws CasterException, PageException {
114                Array arr = ListUtil.listToArray(sld.list, sld.delimiter,sld.includeEmptyFieldsx,sld.multiCharacterDelimiter);
115                
116                Iterator<Entry<Key, Object>> it = arr.entryIterator();
117                Entry<Key, Object> e;
118                while(it.hasNext()){
119                        e = it.next();
120                        initalValue=udf.call(pc, new Object[]{initalValue,e.getValue(),Caster.toDoubleValue(e.getKey().getString()),sld.list,sld.delimiter}, true);
121                }
122                return initalValue;
123        }
124
125        private static Object invoke(PageContext pc, Query qry, UDF udf, Object initalValue) throws CasterException, PageException {
126                final int pid=pc.getId();
127                ForEachQueryIterator it=new ForEachQueryIterator(qry, pid);
128                int rowNbr;
129
130                Object row;
131                while(it.hasNext()){
132                        row = it.next();
133                        rowNbr = qry.getCurrentrow(pid);
134                        initalValue=udf.call(pc, new Object[]{initalValue,row,Caster.toDoubleValue(rowNbr),qry}, true);
135                }
136                return initalValue;
137        }
138        
139
140        private static Object invoke(PageContext pc, List list, UDF udf, Object initalValue) throws CasterException, PageException {
141                ListIterator it = list.listIterator();
142                Object v;
143                int index;
144                ArgumentIntKey k;
145                while(it.hasNext()){
146                        index = it.nextIndex();
147                        k = ArgumentIntKey.init(index);
148            v = it.next();
149            initalValue=udf.call(pc, new Object[]{initalValue,v,Caster.toDoubleValue(k.getString()),list}, true);
150                }
151                return initalValue;
152        }
153
154        private static Object invoke(PageContext pc, Struct sct, UDF udf, Object initalValue) throws PageException {
155                Iterator<Entry<Key, Object>> it = sct.entryIterator();
156                Entry<Key, Object> e;
157                while(it.hasNext()){
158                        e = it.next();
159                        initalValue=udf.call(pc, new Object[]{initalValue,e.getKey().getString(),e.getValue(),sct}, true);
160                }
161                return initalValue;
162        }
163        
164        private static Object invoke(PageContext pc, java.util.Map map, UDF udf, Object initalValue) throws PageException {
165                Iterator<Entry> it = map.entrySet().iterator();
166                Entry e;
167                while(it.hasNext()){
168                        e = it.next();
169                        initalValue=udf.call(pc, new Object[]{initalValue,e.getKey(),e.getValue(),map}, true);
170                }
171                return initalValue;
172        }
173        
174        private static Object invoke(PageContext pc, Iteratorable i, UDF udf, Object initalValue) throws PageException {
175                Iterator<Entry<Key, Object>> it = i.entryIterator();
176                
177                Entry<Key, Object> e;
178                while(it.hasNext()){
179                        e = it.next();
180                        initalValue=udf.call(pc, new Object[]{initalValue,e.getKey().getString(),e.getValue()}, true);
181                }
182                return initalValue;
183        }
184        
185        private static Object invoke(PageContext pc, Iterator it, UDF udf, Object initalValue) throws PageException {
186                
187                Object v;
188                int count=0;
189                ArgumentIntKey k;
190                while(it.hasNext()){
191                        v = it.next();
192                        k = ArgumentIntKey.init(++count);
193                        initalValue=udf.call(pc, new Object[]{initalValue,v}, true);
194                }
195                return initalValue;
196        }
197        
198        private static Object invoke(PageContext pc, Enumeration e, UDF udf, Object initalValue) throws PageException {
199                
200                Object v;
201                int count=0;
202                ArgumentIntKey k;
203                while(e.hasMoreElements()){
204                        v = e.nextElement();
205                        k = ArgumentIntKey.init(++count);
206                        initalValue=udf.call(pc, new Object[]{initalValue,v}, true);
207                }
208                return initalValue;
209        }
210
211        @Override
212        public Object invoke(PageContext pc, Object[] args) throws PageException {
213                if(args.length==2)
214                        return call(pc, (args[0]), Caster.toFunction(args[1]));
215                if(args.length==3)
216                        return call(pc, (args[0]), Caster.toFunction(args[1]), args[2]);
217                
218                throw new FunctionException(pc, "Reduce", 2, 3, args.length);
219        }
220
221}