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.wrap;
020
021import java.util.ArrayList;
022import java.util.Collections;
023import java.util.Comparator;
024import java.util.Iterator;
025import java.util.List;
026import java.util.ListIterator;
027import java.util.Map.Entry;
028
029import lucee.commons.lang.CFTypes;
030import lucee.commons.lang.ExceptionUtil;
031import lucee.runtime.PageContext;
032import lucee.runtime.converter.LazyConverter;
033import lucee.runtime.dump.DumpData;
034import lucee.runtime.dump.DumpProperties;
035import lucee.runtime.dump.DumpUtil;
036import lucee.runtime.exp.ExpressionException;
037import lucee.runtime.exp.PageException;
038import lucee.runtime.exp.PageRuntimeException;
039import lucee.runtime.op.Caster;
040import lucee.runtime.op.Duplicator;
041import lucee.runtime.type.Array;
042import lucee.runtime.type.ArrayImpl;
043import lucee.runtime.type.Collection;
044import lucee.runtime.type.KeyImpl;
045import lucee.runtime.type.Sizeable;
046import lucee.runtime.type.Struct;
047import lucee.runtime.type.dt.DateTime;
048import lucee.runtime.type.it.EntryIterator;
049import lucee.runtime.type.it.KeyIterator;
050import lucee.runtime.type.it.StringIterator;
051import lucee.runtime.type.util.ArrayUtil;
052import lucee.runtime.type.util.MemberUtil;
053
054/**
055 * 
056 */
057public class ListAsArray implements Array,List,Sizeable {
058
059        protected List list;
060        
061        private ListAsArray(List list) {
062                this.list=list;
063        }
064        
065        public static Array toArray(List list) {
066                if(list instanceof ArrayAsList) return ((ArrayAsList)list).array;
067                if(list instanceof Array) return (Array) list;
068                return new ListAsArray(list);
069        }
070        
071        
072        @Override
073        public Object append(Object o) throws PageException {
074                list.add(o);
075                return o;
076        }
077        
078        
079        @Override
080        public Object appendEL(Object o) {
081                list.add(o);
082                return o;
083        }
084
085        @Override
086        public boolean containsKey(int index) {
087                return get(index-1,null)!=null;
088        }
089
090        @Override
091        public Object get(int key, Object defaultValue) {
092                try {
093                        Object rtn = list.get(key-1);
094                        if(rtn==null) return defaultValue;
095                        return rtn;
096                }
097                catch(Throwable t) {
098                        ExceptionUtil.rethrowIfNecessary(t);
099                        return defaultValue;
100                }
101        }
102
103        @Override
104        public Object getE(int key) throws PageException {
105                try {
106                        Object rtn = list.get(key-1);
107                        if(rtn==null) throw new ExpressionException("Element at position ["+key+"] does not exist in list");
108                        return rtn;
109                }
110                catch(Throwable t) {
111                        ExceptionUtil.rethrowIfNecessary(t);
112                        throw new ExpressionException("Element at position ["+key+"] does not exist in list",t.getMessage());
113                }
114        }
115
116        @Override
117        public int getDimension() {
118                return 1;
119        }
120
121        public boolean insert(int key, Object value) throws PageException {
122                try {
123                list.add(key-1, value);
124                }
125                catch(Throwable t) {
126                        ExceptionUtil.rethrowIfNecessary(t);
127                        throw new ExpressionException("can't insert value to array at position "+key+", array goes from 1 to "+size());
128                }
129                return true;
130        }
131
132        public int[] intKeys() {
133                ListIterator lit = list.listIterator();
134                ArrayList keys = new ArrayList();
135                int index=0;
136                Object v;
137                while(lit.hasNext()) {
138                        index=lit.nextIndex()+1;
139                        v=lit.next();
140                        if(v!=null)keys.add(Integer.valueOf(index));
141                }
142                int[] intKeys = new int[keys.size()];
143                Iterator it = keys.iterator();
144                index=0;
145                while(it.hasNext()) {
146                        intKeys[index++]=((Integer)it.next()).intValue();
147                }
148                
149                return intKeys;
150        }
151
152        @Override
153        public Object prepend(Object o) throws PageException {
154                list.add(0,o);
155                return o;
156        }
157
158        public Object removeE(int key) throws PageException {
159                try {
160                return list.remove(key-1);
161                }
162                catch(Throwable t) {
163                        ExceptionUtil.rethrowIfNecessary(t);
164                        throw new ExpressionException("can not remove Element at position ["+key+"]",t.getMessage());
165                }
166        }
167
168        @Override
169        public Object removeEL(int key) {
170                try {
171                        return removeE(key);
172                } catch (PageException e) {
173                        return null;
174                }
175        }
176
177        public void resize(int to) throws PageException {
178                while(size()<to)list.add(null);
179        }
180
181        @Override
182        public Object setE(int key, Object value) throws PageException {
183                if(key<=size()) {
184                        try {
185                        list.set(key-1, value);
186                        }
187                        catch(Throwable t) {
188                                ExceptionUtil.rethrowIfNecessary(t);
189                                throw new ExpressionException("can not set Element at position ["+key+"]",t.getMessage());
190                        }
191                        
192                }
193                else {
194                        while(size()<key-1)list.add(null);
195                        list.add(value);
196                }
197                return value;
198        }
199
200        @Override
201        public Object setEL(int key, Object value) {
202                try {
203                        return setE(key, value);
204                } catch (Throwable t) {
205                        ExceptionUtil.rethrowIfNecessary(t);
206                }
207                return value;
208        }
209
210        @Override
211        public void sort(String sortType, String sortOrder) throws PageException {
212                sort(ArrayUtil.toComparator(null, sortType, sortOrder, false));
213        }
214
215        @Override
216        public synchronized void sort(Comparator comp) {
217                if(getDimension()>1)
218                        throw new PageRuntimeException("only 1 dimensional arrays can be sorted");
219                Collections.sort(list,comp);
220        }
221
222        @Override
223        public Object[] toArray() {
224                return list.toArray();
225        }
226
227        public ArrayList toArrayList() {
228                return new ArrayList(list);
229        }
230
231        @Override
232        public void clear() {
233                list.clear();
234        }
235
236        @Override
237        public boolean containsKey(String key) {
238                return get(key,null)!=null;
239        }
240
241        @Override
242        public boolean containsKey(Key key) {
243                return get(key,null)!=null;
244        }
245
246        @Override
247        public Collection duplicate(boolean deepCopy) {new ArrayImpl().duplicate(deepCopy);
248                return new ListAsArray((List)Duplicator.duplicate(list,deepCopy));
249        }
250
251        
252
253        @Override
254        public Object get(String key) throws PageException {
255                return getE(Caster.toIntValue(key));
256        }
257
258        @Override
259        public Object get(Key key) throws PageException {
260                return get(key.getString());
261        }
262
263        @Override
264        public Object get(String key, Object defaultValue) {
265                double index=Caster.toIntValue(key,Integer.MIN_VALUE);
266                if(index==Integer.MIN_VALUE) return defaultValue;
267            return get((int)index,defaultValue);
268        }
269
270        @Override
271        public Object get(Key key, Object defaultValue) {
272                return get(key.getString(),defaultValue);
273        }
274
275        @Override
276        public Key[] keys() {
277                int[] intKeys = intKeys();
278                Collection.Key[] keys = new Collection.Key[intKeys.length];
279                for(int i=0;i<intKeys.length;i++) {
280                        keys[i]=KeyImpl.init(Caster.toString(intKeys[i]));
281                }
282                return keys;
283        }
284
285        @Override
286        public Object remove(Key key) throws PageException {
287                return removeE(Caster.toIntValue(key.getString()));
288        }
289
290        @Override
291        public Object removeEL(Key key) {
292                double index=Caster.toIntValue(key.getString(),Integer.MIN_VALUE);
293                if(index==Integer.MIN_VALUE) return null;
294            return removeEL((int)index);
295        }
296
297        @Override
298        public Object set(String key, Object value) throws PageException {
299                return setE(Caster.toIntValue(key),value);
300        }
301
302        @Override
303        public Object set(Key key, Object value) throws PageException {
304                return set(key.getString(),value);
305        }
306
307        @Override
308        public Object setEL(String key, Object value) {
309                double index=Caster.toIntValue(key,Integer.MIN_VALUE);
310                if(index==Integer.MIN_VALUE) return value;
311            return setEL((int)index,value);
312        }
313
314        @Override
315        public Object setEL(Key key, Object value) {
316                return setEL(key.getString(), value);
317        }
318
319        @Override
320        public int size() {
321                return list.size();
322        }
323
324        public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
325                return DumpUtil.toDumpData(list, pageContext,maxlevel,dp);
326        }
327
328        @Override
329        public Iterator iterator() {
330                return list.iterator();
331        }
332
333        @Override
334        public Iterator<Collection.Key> keyIterator() {
335                return new KeyIterator(keys());
336        }
337    
338    @Override
339        public Iterator<String> keysAsStringIterator() {
340        return new StringIterator(keys());
341    }
342        
343        @Override
344        public Iterator<Entry<Key, Object>> entryIterator() {
345                return new EntryIterator(this,keys());
346        }
347
348        @Override
349    public String castToString() throws PageException {
350        throw new ExpressionException("Can't cast Complex Object Type "+Caster.toClassName(list)+" to String",
351          "Use Built-In-Function \"serialize(Array):String\" to create a String from Array");
352    }
353
354        @Override
355        public String castToString(String defaultValue) {
356                return defaultValue;
357        }
358
359
360    @Override
361    public boolean castToBooleanValue() throws PageException {
362        throw new ExpressionException("Can't cast Complex Object Type "+Caster.toClassName(list)+" to a boolean value");
363    }
364    
365    @Override
366    public Boolean castToBoolean(Boolean defaultValue) {
367        return defaultValue;
368    }
369
370
371    @Override
372    public double castToDoubleValue() throws PageException {
373        throw new ExpressionException("Can't cast Complex Object Type "+Caster.toClassName(list)+" to a number value");
374    }
375    
376    @Override
377    public double castToDoubleValue(double defaultValue) {
378        return defaultValue;
379    }
380
381
382    @Override
383    public DateTime castToDateTime() throws PageException {
384        throw new ExpressionException("Can't cast Complex Object Type "+Caster.toClassName(list)+" to a Date");
385    }
386    
387    @Override
388    public DateTime castToDateTime(DateTime defaultValue) {
389        return defaultValue;
390    }
391
392        @Override
393        public int compareTo(boolean b) throws PageException {
394                throw new ExpressionException("can't compare Complex Object Type "+Caster.toClassName(list)+" with a boolean value");
395        }
396
397        @Override
398        public int compareTo(DateTime dt) throws PageException {
399                throw new ExpressionException("can't compare Complex Object Type "+Caster.toClassName(list)+" with a DateTime Object");
400        }
401
402        @Override
403        public int compareTo(double d) throws PageException {
404                throw new ExpressionException("can't compare Complex Object Type "+Caster.toClassName(list)+" with a numeric value");
405        }
406
407        @Override
408        public int compareTo(String str) throws PageException {
409                throw new ExpressionException("can't compare Complex Object Type "+Caster.toClassName(list)+" with a String");
410        }
411
412        @Override
413        public String toString() {
414                return LazyConverter.serialize(this);
415        }
416        
417        @Override
418        public Object clone() {
419                return duplicate(true);
420        }
421
422        @Override
423        public boolean add(Object o) {
424                return list.add(o);
425        }
426
427        @Override
428        public void add(int index, Object element) {
429                list.add(index, element);
430        }
431
432        @Override
433        public boolean addAll(java.util.Collection c) {
434                return list.addAll(c);
435        }
436
437        @Override
438        public boolean addAll(int index, java.util.Collection c) {
439                return list.addAll(index, c);
440        }
441
442        @Override
443        public boolean contains(Object o) {
444                return list.contains(o);
445        }
446
447        @Override
448        public boolean containsAll(java.util.Collection c) {
449                return list.contains(c);
450        }
451
452        @Override
453        public Object get(int index) {
454                return list.get(index);
455        }
456
457        @Override
458        public int indexOf(Object o) {
459                return list.indexOf(o);
460        }
461
462        @Override
463        public boolean isEmpty() {
464                return list.isEmpty();
465        }
466
467        @Override
468        public int lastIndexOf(Object o) {
469                return list.lastIndexOf(o);
470        }
471
472        @Override
473        public ListIterator listIterator() {
474                return list.listIterator();
475        }
476
477        @Override
478        public ListIterator listIterator(int index) {
479                return list.listIterator(index);
480        }
481
482        @Override
483        public boolean remove(Object o) {
484                return list.remove(o);
485        }
486
487        @Override
488        public Object remove(int index) {
489                return list.remove(index);
490        }
491
492        @Override
493        public boolean removeAll(java.util.Collection c) {
494                return list.removeAll(c);
495        }
496
497        @Override
498        public boolean retainAll(java.util.Collection c) {
499                return list.retainAll(c);
500        }
501
502        @Override
503        public Object set(int index, Object element) {
504                return list.set(index, element);
505        }
506
507        @Override
508        public List subList(int fromIndex, int toIndex) {
509                return list.subList(fromIndex, toIndex);
510        }
511
512        @Override
513        public Object[] toArray(Object[] a) {
514                return list.toArray(a);
515        }
516
517
518        @Override
519        public List toList() {
520                return this;
521        }
522
523        public Iterator valueIterator() {
524                return list.iterator();
525        }
526
527        @Override
528        public long sizeOf() {
529                return ArrayUtil.sizeOf(list);
530        }
531
532        @Override
533        public Object get(PageContext pc, Key key, Object defaultValue) {
534                return get(key, defaultValue);
535        }
536
537        @Override
538        public Object get(PageContext pc, Key key) throws PageException {
539                return get(key);
540        }
541
542        @Override
543        public Object set(PageContext pc, Key propertyName, Object value) throws PageException {
544                return set(propertyName, value);
545        }
546
547        @Override
548        public Object setEL(PageContext pc, Key propertyName, Object value) {
549                return setEL(propertyName, value);
550        }
551
552        @Override
553        public Object call(PageContext pc, Key methodName, Object[] args) throws PageException {
554                return MemberUtil.call(pc, this, methodName, args, CFTypes.TYPE_ARRAY, "array");
555        }
556
557        @Override
558        public Object callWithNamedValues(PageContext pc, Key methodName, Struct args) throws PageException {
559                return MemberUtil.callWithNamedValues(pc,this,methodName,args, CFTypes.TYPE_ARRAY, "array");
560        }
561
562        @Override
563        public java.util.Iterator<Object> getIterator() {
564        return valueIterator();
565    } 
566}