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.util;
020
021import java.util.AbstractList;
022import java.util.Iterator;
023import java.util.List;
024
025import lucee.commons.lang.CFTypes;
026import lucee.runtime.PageContext;
027import lucee.runtime.converter.LazyConverter;
028import lucee.runtime.exp.ExpressionException;
029import lucee.runtime.exp.PageException;
030import lucee.runtime.exp.PageRuntimeException;
031import lucee.runtime.op.Caster;
032import lucee.runtime.type.Array;
033import lucee.runtime.type.Collection;
034import lucee.runtime.type.KeyImpl;
035import lucee.runtime.type.Objects;
036import lucee.runtime.type.Sizeable;
037import lucee.runtime.type.Struct;
038import lucee.runtime.type.dt.DateTime;
039
040public abstract class ArraySupport extends AbstractList implements Array,List,Sizeable,Objects {
041
042        
043        public static final short TYPE_OBJECT = 0;
044        public static final short TYPE_BOOLEAN = 1;
045        public static final short TYPE_BYTE = 2;
046        public static final short TYPE_SHORT = 3;
047        public static final short TYPE_INT = 4;
048        public static final short TYPE_LONG = 5;
049        public static final short TYPE_FLOAT = 6;
050        public static final short TYPE_DOUBLE = 7;
051        public static final short TYPE_CHARACTER = 8;
052        public static final short TYPE_STRING = 9;
053        
054        @Override
055        public final void add(int index, Object element) {
056                try {
057                        insert(index+1, element);
058                } catch (PageException e) {
059                        throw new IndexOutOfBoundsException("can't insert value to List at position "+index+", " +
060                                        "valid values are from 0 to "+(size()-1)+", size is "+size());
061                }
062        }
063
064        @Override
065        public final boolean addAll(java.util.Collection c) {
066                Iterator it = c.iterator();
067                while(it.hasNext()) {
068                        add(it.next());
069                }
070                return true;
071        }
072        
073        @Override
074        public final boolean remove(Object o) {
075                int index = indexOf(o);
076                if(index==-1) return false;
077                
078                try {
079                        removeE(index+1);
080                } catch (PageException e) {
081                        return false;
082                }
083                return true;
084        }
085
086        @Override
087        public final boolean removeAll(java.util.Collection c) {
088                Iterator it = c.iterator();
089                boolean rtn=false;
090                while(it.hasNext()) {
091                        if(remove(it.next()))rtn=true;
092                }
093                return rtn;
094        }
095
096        @Override
097        public final boolean retainAll(java.util.Collection c) {
098                boolean modified = false;
099                Key[] keys = CollectionUtil.keys(this);
100                Key k;
101                for(int i=keys.length-1;i>=0;i--) {
102                        k = keys[i];
103                        if(!c.contains(get(k,null))) {
104                        removeEL(k);
105                        modified = true;
106                    }
107                }
108                return modified;
109        }
110
111        @Override
112        public final Object[] toArray(Object[] a) {
113                if(a==null) return toArray();
114                
115                
116                Class trgClass=a.getClass().getComponentType();
117                short type=TYPE_OBJECT;
118                if(trgClass==Boolean.class) type=TYPE_BOOLEAN;
119                else if(trgClass==Byte.class) type=TYPE_BYTE;
120                else if(trgClass==Short.class) type=TYPE_SHORT;
121                else if(trgClass==Integer.class) type=TYPE_INT;
122                else if(trgClass==Long.class) type=TYPE_LONG;
123                else if(trgClass==Float.class) type=TYPE_FLOAT;
124                else if(trgClass==Double.class) type=TYPE_DOUBLE;
125                else if(trgClass==Character.class) type=TYPE_CHARACTER;
126                else if(trgClass==String.class) type=TYPE_STRING;
127                
128                
129                Iterator it = iterator();
130                int i=0;
131                Object o;
132                try {
133                        while(it.hasNext()) {
134                                o=it.next();
135                                switch(type){
136                                case TYPE_BOOLEAN:
137                                        o=Caster.toBoolean(o);
138                                break;
139                                case TYPE_BYTE:
140                                        o=Caster.toByte(o);
141                                break;
142                                case TYPE_CHARACTER:
143                                        o=Caster.toCharacter(o);
144                                break;
145                                case TYPE_DOUBLE:
146                                        o=Caster.toDouble(o);
147                                break;
148                                case TYPE_FLOAT:
149                                        o=Caster.toFloat(o);
150                                break;
151                                case TYPE_INT:
152                                        o=Caster.toInteger(o);
153                                break;
154                                case TYPE_LONG:
155                                        o=Caster.toLong(o);
156                                break;
157                                case TYPE_SHORT:
158                                        o=Caster.toShort(o);
159                                break;
160                                case TYPE_STRING:
161                                        o=Caster.toString(o);
162                                break;
163                                }
164                                a[i++]=o;
165                        }
166                }
167                catch(PageException pe){
168                        throw new PageRuntimeException(pe);
169                }
170                return a;
171        }
172
173        @Override
174        public final Object get(int index) {
175                if(index<0)  
176                        throw new IndexOutOfBoundsException("invalid index defintion ["+index+"], " +
177                                        "index should be a number between [0 - "+(size()-1)+"], size is "+size());
178                if(index>=size())
179                        throw new IndexOutOfBoundsException("invalid index ["+index+"] defintion, " +
180                                        "index should be a number between [0 - "+(size()-1)+"], size is "+size());
181                
182                return get(index+1, null); 
183        }
184
185        @Override
186        public final Object remove(int index) {
187                if(index<0)  
188                        throw new IndexOutOfBoundsException("invalid index defintion ["+index+"], " +
189                                        "index should be a number between [0 - "+(size()-1)+"], size is "+size());
190                if(index>=size())
191                        throw new IndexOutOfBoundsException("invalid index ["+index+"] defintion, " +
192                                        "index should be a number between [0 - "+(size()-1)+"], size is "+size());
193                
194                return removeEL(index+1); 
195        }
196
197        @Override
198        public final Object set(int index, Object element) {
199                Object o=get(index);
200                setEL(index+1, element); 
201                return o;
202        }
203        
204
205    @Override
206    public boolean containsKey(String key) {
207        return get(KeyImpl.init(key),null)!=null;
208    }
209    
210    @Override
211    public boolean containsKey(Collection.Key key) {
212        return get(key,null)!=null;
213    }
214
215    @Override
216    public boolean containsKey(int key) {
217        return get(key,null)!=null;
218    }
219
220
221        @Override
222        public String toString() {
223                return LazyConverter.serialize(this);
224        }
225        
226        @Override
227        public synchronized Object clone() {
228                return duplicate(true);
229        }
230
231    @Override
232    public String castToString() throws PageException {
233        throw new ExpressionException("Can't cast Complex Object Type Array to String",
234          "Use Built-In-Function \"serialize(Array):String\" to create a String from Array");
235    }
236
237    @Override
238    public String castToString(String defaultValue) {
239        return defaultValue;
240    }
241
242
243    @Override
244    public boolean castToBooleanValue() throws PageException {
245        throw new ExpressionException("Can't cast Complex Object Type Array to a boolean value");
246    }
247    
248    @Override
249    public Boolean castToBoolean(Boolean defaultValue) {
250        return defaultValue;
251    }
252    
253
254
255    @Override
256    public double castToDoubleValue() throws PageException {
257        throw new ExpressionException("Can't cast Complex Object Type Array to a number value");
258    }
259    
260    @Override
261    public double castToDoubleValue(double defaultValue) {
262        return defaultValue;
263    }
264    
265
266
267    @Override
268    public DateTime castToDateTime() throws PageException {
269        throw new ExpressionException("Can't cast Complex Object Type Array to a Date");
270    }
271    
272    @Override
273    public DateTime castToDateTime(DateTime defaultValue) {
274        return defaultValue;
275    }
276
277        @Override
278        public int compareTo(boolean b) throws PageException {
279                throw new ExpressionException("can't compare Complex Object Type Array with a boolean value");
280        }
281
282        @Override
283        public int compareTo(DateTime dt) throws PageException {
284                throw new ExpressionException("can't compare Complex Object Type Array with a DateTime Object");
285        }
286
287        @Override
288        public int compareTo(double d) throws PageException {
289                throw new ExpressionException("can't compare Complex Object Type Array with a numeric value");
290        }
291
292        @Override
293        public int compareTo(String str) throws PageException {
294                throw new ExpressionException("can't compare Complex Object Type Array with a String");
295        }
296
297        @Override
298        public List toList() {
299                return this;
300        }
301        
302        @Override
303        public Iterator<Object> valueIterator() {
304                return iterator();
305        }
306
307        @Override
308        public Object get(PageContext pc, Key key, Object defaultValue) {
309                return get(key, defaultValue);
310        }
311
312        @Override
313        public Object get(PageContext pc, Key key) throws PageException {
314                return get(key);
315        }
316
317        @Override
318        public Object set(PageContext pc, Key propertyName, Object value) throws PageException {
319                return set(propertyName, value);
320        }
321
322        @Override
323        public Object setEL(PageContext pc, Key propertyName, Object value) {
324                return setEL(propertyName, value);
325        }
326
327        @Override
328        public Object call(PageContext pc, Key methodName, Object[] args) throws PageException {
329                return MemberUtil.call(pc, this, methodName, args, CFTypes.TYPE_ARRAY, "array");
330        }
331
332        @Override
333        public Object callWithNamedValues(PageContext pc, Key methodName, Struct args) throws PageException {
334                return MemberUtil.callWithNamedValues(pc,this,methodName,args, CFTypes.TYPE_ARRAY, "array");
335        }
336
337        @Override
338        public java.util.Iterator<Object> getIterator() {
339        return valueIterator();
340    } 
341
342        @Override
343        public synchronized void sort(String sortType, String sortOrder) throws PageException {
344                if(getDimension()>1)
345                        throw new ExpressionException("only 1 dimensional arrays can be sorted");
346                sort(ArrayUtil.toComparator(null, sortType, sortOrder,false));
347        }
348        
349        @Override
350        public boolean equals(Object obj){
351                if(!(obj instanceof Collection)) return false;
352                return CollectionUtil.equals(this,(Collection)obj);
353        }
354}