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 **/
019/**
020 * Implements the CFML Function arraysort
021 */
022package lucee.runtime.functions.arrays;
023
024import java.util.Arrays;
025import java.util.Collections;
026import java.util.Comparator;
027import java.util.List;
028
029import lucee.runtime.PageContext;
030import lucee.runtime.exp.CasterException;
031import lucee.runtime.exp.FunctionException;
032import lucee.runtime.exp.PageException;
033import lucee.runtime.exp.PageRuntimeException;
034import lucee.runtime.functions.BIF;
035import lucee.runtime.op.Caster;
036import lucee.runtime.type.Array;
037import lucee.runtime.type.Closure;
038import lucee.runtime.type.UDF;
039import lucee.runtime.type.util.ArrayUtil;
040
041public final class ArraySort extends BIF {
042
043        private static final long serialVersionUID = -747941236369495141L;
044        
045        public static boolean call(PageContext pc , Object objArr, Object sortTypeOrClosure) throws PageException {
046                return call(pc , objArr, sortTypeOrClosure, "asc",false);
047        }
048        public static boolean call(PageContext pc , Object objArr, Object sortTypeOrClosure, String sortorder) throws PageException {
049                return call(pc , objArr, sortTypeOrClosure, sortorder,false);
050        }
051        
052        
053        public static boolean call(PageContext pc , Object objArr, Object sortTypeOrClosure, String sortorder, boolean localeSensitive) throws PageException {
054                
055                // Comparator
056                Comparator comp;
057                if(sortTypeOrClosure instanceof UDF)
058                        comp=new UDFComparator(pc, (UDF)sortTypeOrClosure);
059                else 
060                        comp=ArrayUtil.toComparator(pc,Caster.toString(sortTypeOrClosure), sortorder,localeSensitive);
061                
062                // we always need to convert the original object, because we do not return the result
063                if(objArr instanceof Array)                     ((Array)objArr).sort(comp);
064                else if(objArr instanceof List)                 Collections.sort((List)objArr, comp);
065                else if(objArr instanceof Object[])     Arrays.sort((Object[])objArr, comp);
066                // else if(objArr instanceof boolean[]) Arrays.sort((boolean[])objArr);
067                else if(objArr instanceof byte[])               Arrays.sort((byte[])objArr);
068                else if(objArr instanceof char[])               Arrays.sort((char[])objArr);
069                else if(objArr instanceof short[])              Arrays.sort((short[])objArr);
070                else if(objArr instanceof int[])                Arrays.sort((int[])objArr);
071                else if(objArr instanceof long[])               Arrays.sort((long[])objArr);
072                else if(objArr instanceof float[])              Arrays.sort((float[])objArr);
073                else if(objArr instanceof double[])             Arrays.sort((double[])objArr);
074                else throw new FunctionException(pc, "ArraySort", 1, "array", "cannot sort object from type ["+Caster.toTypeName(objArr)+"]");
075                
076                return true;
077        }
078        
079
080        
081        // used for member function
082        public static boolean call(PageContext pc , Array array, Object sortTypeOrClosure) throws PageException {
083                return call(pc , array, sortTypeOrClosure, "asc",false);
084        }
085        
086        public static boolean call(PageContext pc , Array array, Object sortTypeOrClosure, String sortorder) throws PageException {
087                return call(pc , array, sortTypeOrClosure, sortorder,false);
088        }
089        
090        public static boolean call(PageContext pc , Array arr, Object sortTypeOrClosure, String sortorder, boolean localeSensitive) throws PageException {
091                // Comparator
092                Comparator comp;
093                if(sortTypeOrClosure instanceof UDF)
094                        comp=new UDFComparator(pc, (UDF)sortTypeOrClosure);
095                else 
096                        comp=ArrayUtil.toComparator(pc,Caster.toString(sortTypeOrClosure), sortorder,localeSensitive);
097                
098                arr.sort(comp);
099                return true;
100        }
101        
102        @Override
103        public Object invoke(PageContext pc, Object[] args) throws PageException {
104                if(args.length==2)return call(pc,Caster.toArray(args[0]),args[1]);
105                if(args.length==3)return call(pc,Caster.toArray(args[0]),args[1],Caster.toString(args[2]));
106                return call(pc,Caster.toArray(args[0]),args[1],Caster.toString(args[2]),Caster.toBooleanValue(args[3]));
107        }
108}
109
110class UDFComparator implements Comparator<Object> {
111
112        private UDF udf;
113        private Object[] args=new Object[2];
114        private PageContext pc;
115        
116        public UDFComparator(PageContext pc,UDF udf){
117                this.pc=pc;
118                this.udf=udf;
119        }
120
121        @Override
122        public int compare(Object oLeft, Object oRight) {
123                try {
124                        args[0]=oLeft;
125                        args[1]=oRight;
126                        Object res = udf.call(pc, args, false);
127                        Integer i = Caster.toInteger(res,null);
128                        if(i==null) throw new FunctionException(pc,"ArraySort",2,"function","return value of the "+(udf instanceof Closure?"closure":"function ["+udf.getFunctionName()+"]")+" cannot be casted to a integer.",CasterException.createMessage(res, "integer"));
129                return i.intValue();
130                } 
131                catch (PageException pe) {
132                        throw new PageRuntimeException(pe);
133                }
134        }
135
136}