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 **/
019package lucee.runtime.functions.struct;
020
021import java.util.Iterator;
022import java.util.List;
023import java.util.Map;
024import java.util.Map.Entry;
025
026import lucee.runtime.PageContext;
027import lucee.runtime.exp.PageException;
028import lucee.runtime.functions.BIF;
029import lucee.runtime.op.Caster;
030import lucee.runtime.op.Decision;
031import lucee.runtime.type.Collection;
032import lucee.runtime.type.Collection.Key;
033import lucee.runtime.type.KeyImpl;
034import lucee.runtime.type.Struct;
035import lucee.runtime.type.StructImpl;
036
037public class StructKeyTranslate extends BIF {
038        
039        private static final long serialVersionUID = -7978129950865681102L;
040
041        public static double call(PageContext pc ,Struct sct) throws PageException {
042                return call(pc, sct,false,false);
043    }
044        public static double call(PageContext pc ,Struct sct,boolean deepTranslation) throws PageException {
045                return call(pc, sct,deepTranslation,false);
046    }
047        public static double call(PageContext pc ,Struct sct,boolean deepTranslation,boolean leaveOriginalKey) throws PageException {
048                return translate(sct, deepTranslation,leaveOriginalKey);
049    }
050        
051        public static int translate(Collection coll,boolean deep,boolean leaveOrg) throws PageException {
052                Iterator<Entry<Key, Object>> it = coll.entryIterator();
053                Entry<Key, Object> e;
054                boolean isStruct=coll instanceof Struct;
055                String key;
056                int index;
057                int count=0;
058                while(it.hasNext()){
059                        e = it.next();
060                        key=e.getKey().getString();
061                        if(deep)count+=translate(e.getValue(),leaveOrg);
062                        if(isStruct && (index=key.indexOf('.'))!=-1){
063                                count++;
064                                translate(index,e.getKey(),key,coll,leaveOrg);
065                        }
066                }
067                return count;
068    }
069
070        private static int translate(Object value,boolean leaveOrg) throws PageException {
071                if(value instanceof Collection)
072                        return translate((Collection)value, true,leaveOrg);
073                if(value instanceof List)
074                        return translate((List<?>)value, leaveOrg);
075                if(value instanceof Map)
076                        return translate((Map<?,?>)value, leaveOrg);
077                if(Decision.isArray(value))
078                        return translate(Caster.toNativeArray(value), leaveOrg);
079                return 0;
080        }
081
082        private static int translate(List<?> list,boolean leaveOrg) throws PageException {
083                Iterator<?> it = list.iterator();
084                int count=0;
085                while(it.hasNext()){
086                        count+=translate(it.next(),leaveOrg);
087                }
088                return count;
089        }
090
091        private static int translate(Map<?,?> map,boolean leaveOrg) throws PageException {
092                Iterator<?> it = map.entrySet().iterator();
093                int count=0;
094                while(it.hasNext()){
095                        count+=translate(((Map.Entry<?,?>)it.next()).getValue(),leaveOrg);
096                }
097                return count;
098        }
099
100        private static int translate(Object[] arr,boolean leaveOrg) throws PageException {
101                int count=0;
102                for(int i=0;i<arr.length;i++){
103                        count+=translate(arr[i],leaveOrg);
104                }
105                return count;
106        }
107
108        private static void translate(int index, Key key, String strKey, Collection coll,boolean leaveOrg) throws PageException {
109                String left;
110                Object value=leaveOrg?coll.get(key):coll.remove(key);
111                do{
112                        left=strKey.substring(0,index);
113                        strKey=strKey.substring(index+1);
114                        coll=touch(coll,KeyImpl.init(left));
115                        
116                }
117                while((index=strKey.indexOf('.'))!=-1);
118                coll.set(KeyImpl.init(strKey), value);
119        }
120
121        private static Collection touch(Collection coll, Key key) throws PageException {
122                Object obj = coll.get(key,null);
123                if(obj instanceof Collection) return (Collection) obj;
124                if(Decision.isCastableToStruct(obj))
125                        return Caster.toStruct(obj);
126                coll.set(key, coll=new StructImpl());
127                return coll;
128                
129        }
130        @Override
131        public Object invoke(PageContext pc, Object[] args) throws PageException {
132                if(args.length==3) return call(pc,Caster.toStruct(args[0]),Caster.toBooleanValue(args[1]),Caster.toBooleanValue(args[2]));
133                if(args.length==2) return call(pc,Caster.toStruct(args[0]),Caster.toBooleanValue(args[1]));
134                return call(pc,Caster.toStruct(args[0]));
135        }
136        
137}