001    package railo.runtime.op;
002    
003    import java.io.IOException;
004    import java.math.BigDecimal;
005    import java.util.Calendar;
006    import java.util.Date;
007    import java.util.HashSet;
008    import java.util.Iterator;
009    import java.util.List;
010    import java.util.Locale;
011    import java.util.Map;
012    import java.util.Set;
013    
014    import railo.commons.date.DateTimeUtil;
015    import railo.runtime.Component;
016    import railo.runtime.exp.ExpressionException;
017    import railo.runtime.exp.PageException;
018    import railo.runtime.i18n.LocaleFactory;
019    import railo.runtime.op.date.DateCaster;
020    import railo.runtime.type.Collection;
021    import railo.runtime.type.Collection.Key;
022    import railo.runtime.type.dt.DateTime;
023    import railo.runtime.type.dt.DateTimeImpl;
024    import railo.runtime.type.wrap.ListAsArray;
025    import railo.runtime.type.wrap.MapAsStruct;
026    
027    /**
028     * class to compare objects and primitive value types
029     * 
030     * 
031     */
032    public final class Operator {
033            private static final Object NULL = new Object();
034    
035    
036            /** 
037             * compares two Objects 
038             * @param left 
039             * @param right 
040             * @return different of objects as int
041             * @throws PageException
042             */ 
043            public static int compare(Object left, Object right) throws PageException { 
044                    //print.dumpStack();
045                    if(left instanceof String)                      return compare((String)left,right);
046                    else if(left instanceof Number)         return compare(((Number)left).doubleValue(),right);
047                    else if(left instanceof Boolean)        return compare(((Boolean)left).booleanValue(),right);
048                    else if(left instanceof Date)           return compare((Date)left ,right);
049                    else if(left instanceof Castable)       return compare(((Castable)left) ,right); 
050                    else if(left instanceof Locale)         return compare(((Locale)left) ,right); 
051                    else if(left==null)                             return compare("",right);
052                    /*/NICE disabled at the moment left Comparable 
053                    else if(left instanceof Comparable) { 
054                            return ((Comparable)left).compareTo(right);
055                    } */
056                    else if(left instanceof Character)      return compare( ((Character)left).toString() , right ); 
057                    else if(left instanceof Calendar)       return compare( ((Calendar)left).getTime() , right ); 
058                    else {
059                            return error(false,true); 
060                    }
061            } 
062            
063            public static int compare(Locale left, Object right) throws PageException { 
064                    if(right instanceof String)                     return compare(left,(String)right); 
065                    else if(right instanceof Number)        return compare(left,Caster.toString(right)); 
066                    else if(right instanceof Boolean)       return compare(left,Caster.toString(right)); 
067                    else if(right instanceof Date)          return compare(left,Caster.toString(right)); 
068                    else if(right instanceof Castable)      return compare(left,((Castable)right).castToString()); 
069                    else if(right instanceof Locale)        return left.toString().compareTo(right.toString()); 
070                    else if(right==null)                            return compare( left, "" ); 
071                    else if(right instanceof Character)     return compare(left,((Character)right).toString()); 
072                    else if(right instanceof Calendar)      return compare(left, Caster.toString(((Calendar)right).getTime())  ); 
073                    else return error(false,true); 
074            } 
075            
076            public static int compare(Object left, Locale right) throws PageException { 
077                    return -compare(right,left); 
078            }
079            
080            public static int compare(Locale left, String right) { 
081                    Locale rightLocale = LocaleFactory.getLocale(right, null);
082                    if(rightLocale==null) return LocaleFactory.toString(left).compareTo(right);
083                    return left.toString().compareTo(rightLocale.toString());
084            }
085            
086            public static int compare(String left, Locale right) { 
087                    return -compare(right,left);
088            }
089            
090            /** 
091             * compares a Object with a String 
092             * @param left 
093             * @param right 
094             * @return difference as int
095             * @throws PageException
096             */ 
097            public static int compare(Object left, String right) throws PageException { 
098                    if(left instanceof String)                      return compare((String)left, right ); 
099                    else if(left instanceof Number)         return compare( ((Number)left).doubleValue() , right ); 
100                    else if(left instanceof Boolean)        return compare( ((Boolean)left).booleanValue(), right ); 
101                    else if(left instanceof Date)           return compare( (Date)left , right ); 
102                    else if(left instanceof Castable)       return ((Castable)left).compareTo(right ); 
103                    else if(left instanceof Locale)         return compare( (Locale)left , right ); 
104                    else if(left==null)                             return "".compareToIgnoreCase(right);
105                    else if(left instanceof Character)      return compare( ((Character)left).toString() , right ); 
106                    else if(left instanceof Calendar)       return compare( ((Calendar)left).getTime() , right ); 
107                    
108                    else return error(false,true);
109            } 
110    
111            /** 
112             * compares a String with a Object 
113             * @param left 
114             * @param right 
115             * @return difference as int
116             * @throws PageException
117             */ 
118            public static int compare(String left, Object right) throws PageException { 
119                    if(right instanceof String)                     return compare(left,(String)right); 
120                    else if(right instanceof Number)        return compare(left,((Number)right).doubleValue()); 
121                    else if(right instanceof Boolean)       return compare(left,((Boolean)right).booleanValue()?1:0); 
122                    else if(right instanceof Date)          return compare(left,(Date)right); 
123                    else if(right instanceof Castable)      return -((Castable)right).compareTo(left);//compare(left ,((Castable)right).castToString());
124                    else if(right instanceof Locale)        return compare(left ,(Locale)right);
125                    else if(right==null)                            return left.compareToIgnoreCase("");
126                    else if(right instanceof Character)     return compare(left ,((Character)right).toString());
127                    else if(right instanceof Calendar)      return compare(left, ((Calendar)right).getTime()  ); 
128                    else return error(false,true);  
129            } 
130    
131            /** 
132             * compares a Object with a double 
133             * @param left 
134             * @param right 
135             * @return difference as int
136             * @throws PageException
137             */ 
138            public static int compare(Object left, double right) throws PageException { 
139                    if(left instanceof Number)                      return compare( ((Number)left).doubleValue() ,right ); 
140                    else if(left instanceof String)         return compare( (String)left, right ); 
141                    else if(left instanceof Boolean)        return compare( ((Boolean)left).booleanValue()?1D:0D , right ); 
142                    else if(left instanceof Date)           return compare( ((Date)left) ,right); 
143                    else if(left instanceof Castable)       return ((Castable)left).compareTo(right); 
144                    //else if(left instanceof Castable)     return compare(((Castable)left).castToDoubleValue() , right ); 
145                    else if(left instanceof Locale)         return compare( ((Locale)left), Caster.toString(right)); 
146                    else if(left==null)                             return -1;
147                    else if(left instanceof Character)      return compare(((Character)left).toString(),right);
148                    else if(left instanceof Calendar)       return compare( ((Calendar)left).getTime() , right ); 
149                    else {
150                            return error(false,true); 
151                    }
152            } 
153    
154            /** 
155             * compares a double with a Object 
156             * @param left 
157             * @param right 
158             * @return difference as int
159             * @throws PageException
160             */ 
161            public static int compare(double left, Object right) throws PageException { 
162                    if(right instanceof Number)                     return compare(left,((Number)right).doubleValue()); 
163                    else if(right instanceof String)        return compare(left,(String)right); 
164                    else if(right instanceof Boolean)       return compare(left,((Boolean)right).booleanValue()?1D:0D); 
165                    else if(right instanceof Date)          return compare(left,((Date)right)); 
166                    else if(right instanceof Castable)      return -((Castable)right).compareTo(left);//compare(left ,((Castable)right).castToDoubleValue());
167                    else if(right instanceof Locale)        return compare(Caster.toString(left) ,((Locale)right));
168                    else if(right==null)                            return 1;
169                    else if(right instanceof Character)     return compare(left ,((Character)right).toString());
170                    else if(right instanceof Calendar)      return compare(left, ((Calendar)right).getTime() ); 
171                    else return error(true,false);  
172            } 
173    
174            
175            /** 
176             * compares a Object with a boolean 
177             * @param left 
178             * @param right 
179             * @return difference as int
180             * @throws PageException
181             */ 
182            public static int compare(Object left, boolean right) throws PageException { 
183                    if(left instanceof Boolean)                     return compare(((Boolean)left).booleanValue(),right); 
184                    else if(left instanceof String)         return compare((String)left,right); 
185                    else if(left instanceof Number)         return compare(((Number)left).doubleValue(),right?1D:0D); 
186                    else if(left instanceof Date)           return compare(((Date)left),right?1:0); 
187                    else if(left instanceof Castable)       return ((Castable)left).compareTo(right );
188                    else if(left instanceof Locale)         return compare(((Locale)left),Caster.toString(right)); 
189                    else if(left==null)                             return -1;
190                    else if(left instanceof Character)      return compare(((Character)left).toString(),right);
191                    else if(left instanceof Calendar)       return compare( ((Calendar)left).getTime() , right?1:0 ); 
192                    else return error(false,true);  
193            } 
194    
195            /** 
196             * compares a boolean with a Object 
197             * @param left 
198             * @param right 
199             * @return difference as int
200             * @throws PageException
201             */ 
202            public static int compare(boolean left, Object right) throws PageException { 
203                    if(right instanceof Boolean)            return compare(left,((Boolean)right).booleanValue()); 
204                    else if(right instanceof String)        return compare(left?1:0,(String)right); 
205                    else if(right instanceof Number)        return compare(left?1D:0D,((Number)right).doubleValue()); 
206                    else if(right instanceof Date)          return compare(left?1:0,((Date)right)); 
207                    else if(right instanceof Castable)      return -((Castable)right).compareTo(left);//compare(left ,((Castable)right).castToBooleanValue());
208                    else if(right instanceof Locale)        return compare(Caster.toString(left),((Locale)right)); 
209                    else if(right==null)                            return 1;
210                    else if(right instanceof Character)     return compare(left ,((Character)right).toString());
211                    else if(right instanceof Calendar)      return compare(left?1:0, ((Calendar)right).getTime()  ); 
212                    else return error(true,false);  
213            }
214            
215            /** 
216             * compares a Object with a Date 
217             * @param left 
218             * @param right 
219             * @return difference as int
220             * @throws PageException
221             */ 
222            public static int compare(Object left, Date right) throws PageException { 
223                    if(left instanceof String)                      return compare((String)left,right); 
224                    else if(left instanceof Number)         return compare(((Number)left).doubleValue() ,right.getTime()/1000 ); 
225                    else if(left instanceof Boolean)        return compare( ((Boolean)left).booleanValue()?1D:0D , right.getTime()/1000 ); 
226                    else if(left instanceof Date)           return compare( ((Date)left) , right ); 
227                    else if(left instanceof Castable)       return ((Castable)left).compareTo(Caster.toDatetime(right,null) );
228                    else if(left instanceof Locale)         return compare( ((Locale)left) , Caster.toString(right)); 
229                    else if(left==null)                             return compare("", right);
230                    else if(left instanceof Character)      return compare(((Character)left).toString(),right);
231                    else if(left instanceof Calendar)       return compare( ((Calendar)left).getTime() , right ); 
232                    else return error(false,true);  
233            }  
234    
235            /** 
236             * compares a Date with a Object 
237             * @param left 
238             * @param right 
239             * @return difference as int
240             * @throws PageException
241             */ 
242            public static int compare(Date left, Object right) throws PageException { 
243                    if(right instanceof String)                     return compare(left,(String)right); 
244                    else if(right instanceof Number)        return compare(left.getTime()/1000,((Number)right).doubleValue()); 
245                    else if(right instanceof Boolean)       return compare(left.getTime()/1000,((Boolean)right).booleanValue()?1D:0D); 
246                    else if(right instanceof Date)          return compare(left.getTime()/1000,((Date)right).getTime()/1000); 
247                    else if(right instanceof Castable)      return -((Castable)right).compareTo(Caster.toDate(left,null));//compare(left ,(Date)((Castable)right).castToDateTime());
248                    else if(right instanceof Locale)        return compare(Caster.toString(left),(Locale)right); 
249                    else if(right==null)                            return compare(left,"");
250                    else if(right instanceof Character)     return compare(left ,((Character)right).toString());
251                    else if(right instanceof Calendar)      return compare(left.getTime()/1000, ((Calendar)right).getTime().getTime()/1000  ); 
252                    else return error(true,false);  
253            }
254            
255            public static int compare(Castable left, Object right) throws PageException { 
256                    if(right instanceof String)                     return left.compareTo((String)right); 
257                    else if(right instanceof Number)        return left.compareTo(((Number)right).doubleValue()); 
258                    else if(right instanceof Boolean)       return left.compareTo(((Boolean)right).booleanValue()?1d:0d);
259                    else if(right instanceof Date)          return left.compareTo(Caster.toDate(right,null));
260                    else if(right instanceof Castable)      return compare(left.castToString() , ((Castable)right).castToString() ); 
261                    else if(right instanceof Locale)        return compare(left.castToString() , (Locale)right);
262                    else if(right == null)                          return compare(left.castToString(), "" ); 
263                    else if(right instanceof Character)     return left.compareTo(((Character)right).toString());
264                    else if(right instanceof Calendar)      return left.compareTo(new DateTimeImpl(((Calendar)right).getTime()) ); 
265                    else return error(true,false); 
266            }
267            
268            public static int compare(Object left, Castable right) throws PageException { 
269                    return -compare(right,left); 
270            }
271                    
272    
273            /** 
274             * compares a String with a String 
275             * @param left 
276             * @param right 
277             * @return difference as int
278             */
279            public static int compare(String left, String right) { 
280                    if(Decision.isNumeric(left)) {
281                            if(Decision.isNumeric(right)){
282                                    // long numbers
283                                    if(left.length()>9 || right.length()>9) {
284                                            try{
285                                                    return new BigDecimal(left).compareTo(new BigDecimal(right));
286                                            }
287                                            catch(Throwable t){}
288                                    }
289                                    return compare(Caster.toDoubleValue(left,Double.NaN),Caster.toDoubleValue(right,Double.NaN));
290                            }
291                            
292                            return compare(Caster.toDoubleValue(left,Double.NaN),right);
293                    }
294                    if(Decision.isBoolean(left))
295                            return compare(Caster.toBooleanValue(left,false)?1D:0D,right);
296    //               NICE Date compare, perhaps datetime to double
297                    return left.compareToIgnoreCase(right); 
298            }
299    
300        /** 
301         * compares a String with a double 
302         * @param left 
303         * @param right 
304         * @return difference as int
305         */ 
306        public static int compare(String left, double right) { 
307            if(Decision.isNumeric(left)) {
308                if(left.length()>9) {
309                    try{
310                            return new BigDecimal(left).compareTo(new BigDecimal(right));
311                    }
312                    catch(Throwable t){}
313                }
314                    return compare(Caster.toDoubleValue(left,Double.NaN),right); 
315            }
316            if(Decision.isBoolean(left))
317                return compare(Caster.toBooleanValue(left,false),right); 
318            
319            if(left.length()==0) return -1;
320            char leftFirst=left.charAt(0);
321            if(leftFirst>='0' && leftFirst<='9')
322                return left.compareToIgnoreCase(Caster.toString(right));
323            return leftFirst-'0';
324        }
325    
326        /** 
327             * compares a String with a boolean 
328             * @param left 
329             * @param right 
330             * @return difference as int
331             */ 
332            public static int compare(String left, boolean right) { 
333                    if(Decision.isBoolean(left))
334                return compare(Caster.toBooleanValue(left,false),right); 
335                    if(Decision.isNumeric(left))
336                return compare(Caster.toDoubleValue(left,Double.NaN),right?1d:0d); 
337            
338            if(left.length()==0) return -1;
339            char leftFirst=left.charAt(0);
340            //print.ln(left+".compareTo("+Caster.toString(right)+")");
341            //p(left);
342            if(leftFirst>='0' && leftFirst<='9')
343                return left.compareToIgnoreCase(Caster.toString(right?1D:0D));
344            return leftFirst-'0';
345            } 
346    
347            /** 
348             * compares a String with a Date 
349             * @param left 
350             * @param right 
351             * @return difference as int
352             * @throws PageException
353             */ 
354            public static int compare(String left, Date right) throws PageException { 
355                    return -compare(right,left);
356            } 
357    
358            /** 
359             * compares a double with a String 
360             * @param left 
361             * @param right 
362             * @return difference as int
363             */ 
364        public static int compare(double left, String right) { 
365            return -compare(right,left);
366        }
367        
368            /** 
369             * compares a double with a double 
370             * @param left 
371             * @param right 
372             * @return difference as int
373             */ 
374        public static int compare(double left, double right) { 
375            if((left)<(right))return -1; 
376            else if((left)>(right))return 1; 
377            else return 0;
378        }
379    
380            /** 
381             * compares a double with a boolean 
382             * @param left 
383             * @param right 
384             * @return difference as int
385             */ 
386            public static int compare(double left, boolean right) { 
387                            return compare(left,right?1d:0d); 
388            } 
389    
390            /** 
391             * compares a double with a Date 
392             * @param left 
393             * @param right 
394             * @return difference as int
395             */ 
396            public static int compare(double left, Date right) { 
397                            return compare(DateTimeUtil.getInstance().toDateTime(left).getTime()/1000,right.getTime()/1000); 
398            } 
399    
400            /** 
401             * compares a boolean with a double 
402             * @param left 
403             * @param right 
404             * @return difference as int
405             */ 
406            public static int compare(boolean left, double right) { 
407                            return compare(left?1d:0d, right); 
408            } 
409    
410            /** 
411             * compares a boolean with a double 
412             * @param left 
413             * @param right 
414             * @return difference as int
415             */ 
416            public static int compare(boolean left, String right) { 
417                            return -compare(right,left); 
418            } 
419    
420            /** 
421             * compares a boolean with a boolean 
422             * @param left 
423             * @param right 
424             * @return difference as int
425             */ 
426            public static int compare(boolean left, boolean right) { 
427                            if(left)return right?0:1; 
428                            return right?-1:0; 
429            } 
430    
431            /** 
432             * compares a boolean with a Date 
433             * @param left 
434             * @param right 
435             * @return difference as int
436             */ 
437            public static int compare(boolean left, Date right) { 
438                            return compare(left?1D:0D,right); 
439            } 
440    
441            /** 
442             * compares a Date with a String 
443             * @param left 
444             * @param right 
445             * @return difference as int
446             * @throws PageException
447             */ 
448            public static int compare(Date left, String right) throws PageException { 
449                    if(Decision.isNumeric(right)) return compare(left.getTime()/1000,Caster.toDoubleValue(right));
450                    DateTime dt=DateCaster.toDateAdvanced(right,true,null,null);
451                    if(dt!=null) {
452                            return compare(left.getTime()/1000,dt.getTime()/1000);          
453                    }
454                    return Caster.toString(left).compareToIgnoreCase(right);
455            } 
456    
457            /** 
458             * compares a Date with a double 
459             * @param left 
460             * @param right 
461             * @return difference as int
462             */ 
463            public static int compare(Date left, double right) { 
464                            return compare(left.getTime()/1000, DateTimeUtil.getInstance().toDateTime(right).getTime()/1000); 
465            } 
466    
467            /** 
468             * compares a Date with a boolean 
469             * @param left 
470             * @param right 
471             * @return difference as int
472             */ 
473            public static int compare(Date left, boolean right) { 
474                            return compare(left,right?1D:0D); 
475            } 
476    
477            /** 
478             * compares a Date with a Date 
479             * @param left 
480             * @param right 
481             * @return difference as int
482             */ 
483            public static int compare(Date left, Date right) { 
484                            return compare(left.getTime()/1000,right.getTime()/1000); 
485            }        
486    
487            private static int error(boolean leftIsOk, boolean rightIsOk) throws ExpressionException { 
488                    // TODO remove this method
489                    throw new ExpressionException("can't compare complex object types as simple value");
490            }
491    
492            /**
493             * Method to compare to different values, return true of objects are same otherwise false
494             * @param left left value to compare
495             * @param right right value to compare
496             * @param caseSensitive check case sensitive  or not
497             * @return is same or not
498             * @throws PageException
499             */
500            public static boolean equals(Object left, Object right, boolean caseSensitive) throws PageException {
501                    if(caseSensitive) {
502                            try {
503                                    return Caster.toString(left).equals(Caster.toString(right));
504                            } catch (ExpressionException e) {
505                                    return compare(left,right)==0;
506                            }
507                    }
508                    return compare(left,right)==0;
509            }
510            
511            public static boolean equalsEL(Object left, Object right, boolean caseSensitive, boolean allowComplexValues) {
512                    if(!allowComplexValues || (Decision.isSimpleValue(left) && Decision.isSimpleValue(right))){
513                            try {
514                                    return equals(left, right, caseSensitive);
515                            } catch (PageException e) {
516                                    return false;
517                            }
518                    }
519                    return equalsComplexEL(left, right, caseSensitive,false);
520            }
521            
522            public static boolean equalsComplexEL(Object left, Object right, boolean caseSensitive, boolean checkOnlyPublicAppearance) {
523                    return _equalsComplexEL(null,left, right, caseSensitive,checkOnlyPublicAppearance);
524            }
525            
526            public static boolean _equalsComplexEL(Set<Object> done,Object left, Object right, boolean caseSensitive, boolean checkOnlyPublicAppearance) {
527                    if(left==right) return true;
528                    if(Decision.isSimpleValue(left) && Decision.isSimpleValue(right)){
529                            try {
530                                    return equals(left, right, caseSensitive);
531                            } catch (PageException e) {
532                                    return false;
533                            }
534                    }
535                    if(left==null) return right==null;
536                    
537                    if(done==null)done=new HashSet<Object>();
538                    else if(done.contains(left) && done.contains(right)) return true;
539                    done.add(left);
540                    done.add(right);
541                    
542                    if(left instanceof Component && right instanceof Component)
543                            return __equalsComplexEL(done,(Component)left, (Component)right,caseSensitive,checkOnlyPublicAppearance);
544                    
545                    if(left instanceof Collection && right instanceof Collection)
546                            return __equalsComplexEL(done,(Collection)left, (Collection)right,caseSensitive,checkOnlyPublicAppearance);
547                    
548                    if(left instanceof List && right instanceof List)
549                            return __equalsComplexEL(done,ListAsArray.toArray((List)left), ListAsArray.toArray((List)right),caseSensitive,checkOnlyPublicAppearance);
550                    
551                    if(left instanceof Map && right instanceof Map)
552                            return __equalsComplexEL(done,MapAsStruct.toStruct((Map)left,true), MapAsStruct.toStruct((Map)right,true),caseSensitive,checkOnlyPublicAppearance);
553                    return left.equals(right);
554            }
555            
556            private static boolean __equalsComplexEL(Set<Object> done,Component left, Component right,boolean caseSensitive, boolean checkOnlyPublicAppearance) {
557                    if(left==null || right==null) {
558                            if(left==right) return true;
559                            return false;
560                    }
561                    if(!left.getPageSource().equals(right.getPageSource())) return false;
562                    if(!checkOnlyPublicAppearance && !__equalsComplexEL(done,left.getComponentScope(),right.getComponentScope(), caseSensitive,checkOnlyPublicAppearance)) return false;
563                    if(!__equalsComplexEL(done,(Collection)left,(Collection)right, caseSensitive,checkOnlyPublicAppearance)) return false;
564                    return true;
565            }
566            
567            private static boolean __equalsComplexEL(Set<Object> done,Collection left, Collection right,boolean caseSensitive, boolean checkOnlyPublicAppearance) {
568                    if(left.size()!=right.size()) return false;
569                    Iterator<Key> it = left.keyIterator();
570                    Key k;
571                    Object l,r;
572                    while(it.hasNext()){
573                            k=it.next();
574                            l=left.get(k,NULL);
575                            r=right.get(k,NULL);
576                            if(l==NULL || r==NULL) {
577                                    if(l==r) continue;
578                                    return false;
579                            }
580                            
581                            if(!_equalsComplexEL(done,r, l, caseSensitive,checkOnlyPublicAppearance)) {
582                                    return false;
583                            }
584                    }
585                    return true;
586            }
587            
588            
589            public static boolean equals(Object left, Object right, boolean caseSensitive, boolean allowComplexValues) throws PageException {
590                    if(!allowComplexValues || (Decision.isSimpleValue(left) && Decision.isSimpleValue(right)))
591                            return equals(left, right, caseSensitive);
592                    return equalsComplex(left, right, caseSensitive);
593            }
594    
595            public static boolean equalsComplex(Object left, Object right, boolean caseSensitive) throws PageException {
596                    return _equalsComplex(null,left, right, caseSensitive);
597            }
598            
599    
600            public static boolean _equalsComplex(Set<Object> done,Object left, Object right, boolean caseSensitive) throws PageException {
601                    if(Decision.isSimpleValue(left) && Decision.isSimpleValue(right)){
602                            return equals(left, right, caseSensitive);
603                    }
604                    if(left==null) return right==null;
605                    if(done==null)done=new HashSet<Object>();
606                    else if(done.contains(left) && done.contains(right)) return true;
607                    done.add(left);
608                    done.add(right);
609                    
610                    if(left instanceof Collection && right instanceof Collection)
611                            return __equalsComplex(done,(Collection)left, (Collection)right,caseSensitive);
612                    
613                    if(left instanceof List && right instanceof List)
614                            return __equalsComplex(done,ListAsArray.toArray((List)left), ListAsArray.toArray((List)right),caseSensitive);
615                    
616                    if(left instanceof Map && right instanceof Map)
617                            return __equalsComplex(done,MapAsStruct.toStruct((Map)left,true), MapAsStruct.toStruct((Map)right,true),caseSensitive);
618                    
619                    return left.equals(right);
620            }
621            
622            private static boolean __equalsComplex(Set<Object> done,Collection left, Collection right,boolean caseSensitive) throws PageException {
623                    if(left.size()!=right.size()) return false;
624                    Iterator<Key> it = left.keyIterator();
625                    Key k;
626                    Object l,r;
627                    while(it.hasNext()){
628                            k=it.next();
629                            r=right.get(k,NULL);
630                            if(r==NULL) return false;
631                            l=left.get(k,NULL);
632                            if(!_equalsComplex(done,r, l, caseSensitive)) return false;
633                    }
634                    return true;
635            }
636            
637            /**
638             * check if left is inside right (String-> ignore case)
639             * @param left string to check
640             * @param right substring to find in string
641             * @return return if substring has been found
642             * @throws PageException
643             */
644            public static boolean ct(Object left, Object right) throws PageException {
645                    return Caster.toString(left).toLowerCase().indexOf(Caster.toString(right).toLowerCase())!=-1;           
646            } 
647    
648            /**
649             * Equivalence: Return True if both operands are True or both are False. The EQV operator is the opposite of the XOR operator. For example, True EQV True is True, but True EQV False is False.
650             * @param left value to check
651             * @param right value to check
652             * @return result of operation
653             * @throws PageException
654             */
655            public static boolean eqv(Object left, Object right) throws PageException {
656                    return eqv(Caster.toBooleanValue(left),Caster.toBooleanValue(right));   
657            }
658    
659            /**
660             * Equivalence: Return True if both operands are True or both are False. The EQV operator is the opposite of the XOR operator. For example, True EQV True is True, but True EQV False is False.
661             * @param left value to check
662             * @param right value to check
663             * @return result of operation
664             */
665            public static boolean eqv(boolean left, boolean right) {
666                    return (left==true && right==true) || (left==false && right==false);    
667            }
668    
669            /**
670             * Implication: The statement A IMP B is the equivalent of the logical statement 
671             * "If A Then B." A IMP B is False only if A is True and B is False. It is True in all other cases.
672             * @param left value to check
673             * @param right value to check
674             * @return result
675             * @throws PageException
676             */
677            public static boolean imp(Object left, Object right) throws PageException {
678                    return imp(Caster.toBooleanValue(left),Caster.toBooleanValue(right));   
679            } 
680    
681            /**
682             * Implication: The statement A IMP B is the equivalent of the logical statement 
683             * "If A Then B." A IMP B is False only if A is True and B is False. It is True in all other cases.
684             * @param left value to check
685             * @param right value to check
686             * @return result
687             */
688            public static boolean imp(boolean left, boolean right) {
689                    return !(left==true && right==false);   
690            } 
691    
692            /**
693             * check if left is not inside right (String-> ignore case)
694             * @param left string to check
695             * @param right substring to find in string
696             * @return return if substring NOT has been found
697             * @throws PageException
698             */
699            public static boolean nct(Object left, Object right) throws PageException {
700                    return !ct(left,right);         
701            }
702    
703    
704            /**
705             * simple reference compersion
706             * @param left
707             * @param right
708             * @return
709             * @throws PageException
710             */
711            public static boolean eeq(Object left, Object right) throws PageException {
712                    return left==right;             
713            }
714    
715    
716            /**
717             * simple reference compersion
718             * @param left
719             * @param right
720             * @return
721             * @throws PageException
722             */
723            public static boolean neeq(Object left, Object right) throws PageException {
724                    return left!=right;             
725            }
726            
727            /**
728             * calculate the exponent of the left value 
729             * @param left value to get exponent from
730             * @param right exponent count
731             * @return return expoinended value
732             * @throws PageException
733             */
734            public static double exponent(Object left, Object right) throws PageException {
735                    return StrictMath.pow(Caster.toDoubleValue(left),Caster.toDoubleValue(right));
736            } 
737            
738            public static double exponent(double left, double right) {
739                    return StrictMath.pow(left,right);
740            } 
741            
742            public static double intdiv(double left, double right) {
743                    return ((int)left)/((int)right);
744            } 
745            
746            public static double div(double left, double right) {
747                    if(right==0d)
748                            throw new ArithmeticException("Division by zero is not possible");
749                    return left/right;
750            } 
751            
752            public static float exponent(float left, float right) {
753                    return (float) StrictMath.pow(left,right);
754            } 
755        
756    
757        /**
758         * concat 2 CharSequences
759         * @param left
760         * @param right
761         * @return concated String
762         */
763            public static CharSequence concat(CharSequence left, CharSequence right) {
764                    if(left instanceof Appendable) {
765                            try {
766                                    ((Appendable)left).append(right);
767                                    return left;
768                            } catch (IOException e) {}
769                    }
770                    return new StringBuilder(left).append(right);
771            }
772    
773        /**
774         * plus operation
775         * @param left
776         * @param right
777         * @return result of the opertions
778         */
779        public final static double plus(double left, double right) {
780            return left+right;
781        }
782        
783        /**
784         * minus operation
785         * @param left
786         * @param right
787         * @return result of the opertions
788         */
789        public static double minus(double left, double right) {
790            return left-right;
791        }
792        
793        /**
794         * modulus operation
795         * @param left
796         * @param right
797         * @return result of the opertions
798         */
799        public static double modulus(double left, double right) {
800            return left%right;
801        }
802        
803        /**
804         * divide operation
805         * @param left
806         * @param right
807         * @return result of the opertions
808         */
809        public static double divide(double left, double right) {
810            return left/right;
811        }
812        
813        /**
814         * multiply operation
815         * @param left
816         * @param right
817         * @return result of the opertions
818         */
819        public static double multiply(double left, double right) {
820            return left*right;
821        }
822    
823        /**
824         * bitand operation
825         * @param left
826         * @param right
827         * @return result of the opertions
828         */
829        public static double bitand(double left, double right) {
830            return (int)left&(int)right;
831        }
832    
833        /**
834         * bitand operation
835         * @param left
836         * @param right
837         * @return result of the opertions
838         */
839        public static double bitor(double left, double right) {
840            return (int)left|(int)right;
841        }
842        
843    
844        public static Double divRef(Object left, Object right) throws PageException {
845                    double r = Caster.toDoubleValue(right);
846            if(r==0d)
847                            throw new ArithmeticException("Division by zero is not possible");
848                    return Caster.toDouble(Caster.toDoubleValue(left)/r);
849            }
850        
851        public static Double exponentRef(Object left, Object right) throws PageException {
852                    return Caster.toDouble(StrictMath.pow(Caster.toDoubleValue(left),Caster.toDoubleValue(right)));
853            }
854        
855        public static Double intdivRef(Object left, Object right) throws PageException {
856                    return Caster.toDouble(Caster.toIntValue(left)/Caster.toIntValue(right));
857            }
858        
859        public static Double plusRef(Object left, Object right) throws PageException {
860                    return Caster.toDouble(Caster.toDoubleValue(left)+Caster.toDoubleValue(right));
861            }
862        
863        public static Double minusRef(Object left, Object right) throws PageException {
864                    return Caster.toDouble(Caster.toDoubleValue(left)-Caster.toDoubleValue(right));
865            }
866        
867        public static Double modulusRef(Object left, Object right) throws PageException {
868                    return Caster.toDouble(Caster.toDoubleValue(left)%Caster.toDoubleValue(right));
869            }
870        
871        public static Double divideRef(Object left, Object right) throws PageException {
872                    return Caster.toDouble(Caster.toDoubleValue(left)/Caster.toDoubleValue(right));
873            }
874        
875        public static Double multiplyRef(Object left, Object right) throws PageException {
876                    return Caster.toDouble(Caster.toDoubleValue(left)*Caster.toDoubleValue(right));
877            }
878    }