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 structfindvalue
021 */
022package lucee.runtime.functions.struct;
023
024import java.util.Iterator;
025import java.util.Map.Entry;
026
027import lucee.runtime.PageContext;
028import lucee.runtime.exp.FunctionException;
029import lucee.runtime.exp.PageException;
030import lucee.runtime.functions.BIF;
031import lucee.runtime.op.Caster;
032import lucee.runtime.type.Array;
033import lucee.runtime.type.ArrayImpl;
034import lucee.runtime.type.Collection;
035import lucee.runtime.type.Collection.Key;
036import lucee.runtime.type.Struct;
037import lucee.runtime.type.StructImpl;
038import lucee.runtime.type.util.KeyConstants;
039
040public final class StructFindValue extends BIF {
041
042        private static final long serialVersionUID = 1499023912262918840L;
043
044        public static Array call(PageContext pc , lucee.runtime.type.Struct struct, String value) throws PageException {
045                return call(pc,struct,value,"one");
046        }
047        public static Array call(PageContext pc , Struct struct, String value, String scope) throws PageException {
048                // Scope
049            boolean all=false;
050            if(scope.equalsIgnoreCase("one")) all=false;
051            else if(scope.equalsIgnoreCase("all")) all=true;
052            else throw new FunctionException(pc,"structFindValue",3,"scope","invalid scope definition ["+scope+"], valid scopes are [one, all]");
053            
054            Array array=new ArrayImpl();
055            getValues(pc,array,struct,value,all,"");
056            return array;
057        }
058    /**
059     * @param coll
060     * @param value
061     * @param all
062     * @param buffer
063     * @return
064     * @throws PageException
065     */
066    private static boolean getValues(PageContext pc,Array array,Collection coll, String value, boolean all, String path) throws PageException {
067        //Key[] keys = coll.keys();
068        boolean abort=false;
069        Key key;
070        Iterator<Entry<Key, Object>> it = coll.entryIterator();
071        Entry<Key, Object> e;
072        loop:while(it.hasNext()) {
073                e = it.next();
074            if(abort)break loop;
075            key=e.getKey();
076            Object o=e.getValue();
077            
078            // Collection (this function search first for sub)
079            if(o instanceof Collection) {
080                abort=getValues(pc,array,((Collection)o), value, all, StructFindKey.createKey(coll, path, key));
081                
082            }
083            // matching value
084            if(!abort && !StructFindKey.isArray(coll)){
085            String target=Caster.toString(o,null);
086            if((target!=null && target.equalsIgnoreCase(value)) /*|| (o instanceof Array && checkSub(array,((Array)o),value,all,path,abort))*/) {
087                Struct sct=new StructImpl();
088                        sct.setEL(KeyConstants._key,key.getString());
089                                sct.setEL(KeyConstants._path,StructFindKey.createKey(coll, path, key));
090                                sct.setEL(KeyConstants._owner,coll);
091                array.append(sct);
092                if(!all)abort=true;
093            }
094        }
095        }
096        
097        return abort;
098    }
099    
100        @Override
101        public Object invoke(PageContext pc, Object[] args) throws PageException {
102                if(args.length==3) return call(pc,Caster.toStruct(args[0]),Caster.toString(args[1]),Caster.toString(args[2]));
103                return call(pc,Caster.toStruct(args[0]),Caster.toString(args[1]));
104        }
105}