001    /**
002     * Implements the CFML Function structfindkey
003     */
004    package railo.runtime.functions.struct;
005    
006    import java.util.Iterator;
007    import java.util.List;
008    import java.util.Map;
009    import java.util.Map.Entry;
010    
011    import railo.runtime.PageContext;
012    import railo.runtime.exp.FunctionException;
013    import railo.runtime.exp.PageException;
014    import railo.runtime.ext.function.Function;
015    import railo.runtime.type.Array;
016    import railo.runtime.type.ArrayImpl;
017    import railo.runtime.type.Collection;
018    import railo.runtime.type.Collection.Key;
019    import railo.runtime.type.Struct;
020    import railo.runtime.type.StructImpl;
021    import railo.runtime.type.scope.Argument;
022    import railo.runtime.type.util.KeyConstants;
023    import railo.runtime.type.wrap.ListAsArray;
024    import railo.runtime.type.wrap.MapAsStruct;
025    
026    public final class StructFindKey implements Function {
027            
028            public static Array call(PageContext pc , railo.runtime.type.Struct struct, String value) throws PageException {
029                    return _call(pc,struct,value,false);
030            }
031        public static Array call(PageContext pc , Struct struct, String value, String scope) throws PageException {
032            // Scope
033            boolean all=false;
034            if(scope.equalsIgnoreCase("one")) all=false;
035            else if(scope.equalsIgnoreCase("all")) all=true;
036            else throw new FunctionException(pc,"structFindValue",3,"scope","invalid scope definition ["+scope+"], valid scopes are [one, all]");
037            return _call(pc,struct,value,all);
038        }
039        private static Array _call(PageContext pc , Struct struct, String value, boolean all) throws PageException {
040            Array array=new ArrayImpl();
041            getValues(array,struct,value,all,"");
042            return array;
043        }
044        /**
045         * @param coll
046         * @param value
047         * @param all
048         * @param buffer
049         * @return
050         * @throws PageException
051         */
052        private static boolean getValues(Array array,Collection coll, String value, boolean all, String path) throws PageException {
053            //Collection.Key[] keys=coll.keys();
054            Iterator<Entry<Key, Object>> it = coll.entryIterator();
055            Entry<Key, Object> e;
056            boolean abort=false;
057            Collection.Key key;
058            
059            while(it.hasNext()) {
060                    e = it.next();
061                if(abort)break;
062                key=e.getKey();
063                Object o=e.getValue();
064    
065                // matching value  (this function search first for base)
066                if(key.getString().equalsIgnoreCase(value)) {
067                    Struct sct=new StructImpl();
068                    
069                        sct.setEL(KeyConstants._value,o);
070                    sct.setEL(KeyConstants._path,createKey(coll,path,key));
071                    sct.setEL(KeyConstants._owner,coll);
072                    array.append(sct);
073                    if(!all)abort=true;
074                }
075                
076                // Collection
077                if(!abort) {
078                        if(o instanceof Collection) {
079                            abort=getValues(array,((Collection)o), value, all, createKey(coll,path,key));
080                        }
081                        else if(o instanceof List){
082                            abort=getValues(array,ListAsArray.toArray((List)o), value, all, createKey(coll,path,key));
083                        }
084                        else if(o instanceof Map){
085                            abort=getValues(array,MapAsStruct.toStruct((Map)o), value, all, createKey(coll,path,key));
086                        }
087                }
088            }
089            
090            return abort;
091        }
092            static String createKey(Collection coll,String path,Collection.Key key) {
093                    StringBuffer p=new StringBuffer(path.toString());
094            if(isArray(coll)){
095                    p.append('[').append(key.getString()).append(']');
096            }
097            else{
098                    p.append('.').append(key.getString());
099            }
100                    return p.toString();
101            }
102            static boolean isArray(Collection coll) {
103                    return coll instanceof Array && !(coll instanceof Argument);
104            }
105    }