001    /**
002     * Implements the Cold Fusion Function structfindkey
003     */
004    package railo.runtime.functions.struct;
005    
006    import railo.runtime.PageContext;
007    import railo.runtime.exp.FunctionException;
008    import railo.runtime.exp.PageException;
009    import railo.runtime.ext.function.Function;
010    import railo.runtime.type.Array;
011    import railo.runtime.type.ArrayImpl;
012    import railo.runtime.type.Collection;
013    import railo.runtime.type.KeyImpl;
014    import railo.runtime.type.Struct;
015    import railo.runtime.type.StructImpl;
016    import railo.runtime.type.scope.Argument;
017    
018    public final class StructFindKey implements Function {
019            
020            public static Array call(PageContext pc , railo.runtime.type.Struct struct, String value) throws PageException {
021                    return _call(pc,struct,value,false);
022            }
023        public static Array call(PageContext pc , Struct struct, String value, String scope) throws PageException {
024            // Scope
025            boolean all=false;
026            if(scope.equalsIgnoreCase("one")) all=false;
027            else if(scope.equalsIgnoreCase("all")) all=true;
028            else throw new FunctionException(pc,"structFindValue",3,"scope","invalid scope definition ["+scope+"], valid scopes are [one, all]");
029            return _call(pc,struct,value,all);
030        }
031        private static Array _call(PageContext pc , Struct struct, String value, boolean all) throws PageException {
032            Array array=new ArrayImpl();
033            getValues(array,struct,value,all,"");
034            return array;
035        }
036        /**
037         * @param coll
038         * @param value
039         * @param all
040         * @param buffer
041         * @return
042         * @throws PageException
043         */
044        private static boolean getValues(Array array,Collection coll, String value, boolean all, String path) throws PageException {
045            Collection.Key[] keys=coll.keys();
046            boolean abort=false;
047            Collection.Key key;
048            
049            for(int i=0;i<keys.length;i++) {
050                if(abort)break;
051                key=keys[i];
052                Object o=coll.get(key);
053    
054                // matching value  (this function search first for base)
055                if(key.getString().equalsIgnoreCase(value)) {
056                    Struct sct=new StructImpl();
057                    
058                        sct.setEL(KeyImpl.VALUE,o);
059                    sct.setEL(KeyImpl.PATH,createKey(coll,path,key));
060                    sct.setEL(KeyImpl.OWNER,coll);
061                    array.append(sct);
062                    if(!all)abort=true;
063                }
064                
065                // Collection
066                if(!abort && o instanceof Collection) {
067                    abort=getValues(array,((Collection)o), value, all, createKey(coll,path,key));
068                }
069            }
070            
071            return abort;
072        }
073            static String createKey(Collection coll,String path,Collection.Key key) {
074                    StringBuffer p=new StringBuffer(path.toString());
075            if(isArray(coll)){
076                    p.append('[').append(key.getString()).append(']');
077            }
078            else{
079                    p.append('.').append(key.getString());
080            }
081                    return p.toString();
082            }
083            static boolean isArray(Collection coll) {
084                    return coll instanceof Array && !(coll instanceof Argument);
085            }
086    }