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.type.scope;
020
021import java.util.Iterator;
022
023import lucee.runtime.PageContext;
024import lucee.runtime.config.NullSupportHelper;
025import lucee.runtime.dump.DumpData;
026import lucee.runtime.dump.DumpProperties;
027import lucee.runtime.dump.DumpTable;
028import lucee.runtime.engine.ThreadLocalPageContext;
029import lucee.runtime.exp.PageException;
030import lucee.runtime.op.Duplicator;
031import lucee.runtime.type.Collection;
032import lucee.runtime.type.StructImpl;
033
034public class ClosureScope extends ScopeSupport implements Variables {
035        
036        private static final Object NULL = new Object();
037        private Argument arg;
038        private Local local;
039        private Variables var;
040        public Argument getArgument() {
041                return arg;
042        }
043
044        public Variables getVariables() {
045                return var;
046        }
047
048        public Undefined getUndefined() {
049                return und;
050        }
051
052        private boolean debug;
053        private Undefined und; 
054
055        public ClosureScope(PageContext pc,Argument arg, Local local,Variables var ){
056                super("variables",SCOPE_VARIABLES,StructImpl.TYPE_UNDEFINED);
057                arg.setBind(true);
058                local.setBind(true);
059                var.setBind(true);
060                und = pc.undefinedScope();
061                this.arg=arg;
062                this.local=local;
063                this.var=var;
064                this.debug=pc.getConfig().debug();
065        }
066
067        @Override
068        public boolean isInitalized() {
069                return true;
070        }
071
072        @Override
073        public void initialize(PageContext pc) {        
074        }
075
076        @Override
077        public void release() {
078        }
079
080        @Override
081        public void release(PageContext pc) {
082        }
083
084        @Override
085        public int getType() {
086                return SCOPE_VARIABLES;
087        }
088
089        @Override
090        public String getTypeAsString() {
091                return "variables";
092        }
093
094        @Override
095        public int size() {
096                return var.size();
097        }
098
099        @Override
100        public Key[] keys() {
101                return var.keys();
102        }
103
104        @Override
105        public Object remove(Key key) throws PageException {
106                if(local.containsKey(key))
107                        return local.remove(key);
108                return var.remove(key);
109        }
110
111        @Override
112        public Object removeEL(Key key) {
113                if(local.containsKey(key))
114                        return local.removeEL(key);
115                return var.removeEL(key);
116        }
117
118        @Override
119        public void clear() {
120                var.clear();
121        }
122
123        @Override
124        public Object get(Key key) throws PageException {
125                Object value = local.get(key,NullSupportHelper.NULL());
126                if(value!=NullSupportHelper.NULL()) return value;
127                value=arg.get(key,NullSupportHelper.NULL());
128                if(value!=NullSupportHelper.NULL()) {
129                        if(debug) UndefinedImpl.debugCascadedAccess(ThreadLocalPageContext.get(),arg.getTypeAsString(), key);
130                        return value;
131                }
132                
133                value= var.get(key);
134                if(debug) UndefinedImpl.debugCascadedAccess(ThreadLocalPageContext.get(),var.getTypeAsString(), key);
135                return value;
136        }
137
138        @Override
139        public Object get(Key key, Object defaultValue) {
140                Object value = local.get(key,NullSupportHelper.NULL());
141                if(value!=NullSupportHelper.NULL()) return value;
142                value=arg.get(key,NullSupportHelper.NULL());
143                if(value!=NullSupportHelper.NULL()) {
144                        if(debug) UndefinedImpl.debugCascadedAccess(ThreadLocalPageContext.get(),arg.getTypeAsString(), key);
145                        return value;
146                }
147                value= var.get(key,NullSupportHelper.NULL());
148                if(value!=NullSupportHelper.NULL()){
149                        if(debug) UndefinedImpl.debugCascadedAccess(ThreadLocalPageContext.get(),var.getTypeAsString(), key);
150                        return value;
151                }
152                return defaultValue;
153        }
154
155        @Override
156        public Object set(Key key, Object value) throws PageException {
157                if(und.getLocalAlways() || local.containsKey(key))     return local.set(key,value);
158            if(arg.containsKey(key))  {
159                if(debug)UndefinedImpl.debugCascadedAccess(ThreadLocalPageContext.get(),arg.getTypeAsString(), key);
160                return arg.set(key,value);
161            }
162            if(debug)UndefinedImpl.debugCascadedAccess(ThreadLocalPageContext.get(),var.getTypeAsString(), key);
163                return var.set(key, value);
164        }
165
166        @Override
167        public Object setEL(Key key, Object value) {
168            if(und.getLocalAlways() || local.containsKey(key))     return local.setEL(key,value);
169        if(arg.containsKey(key))  {
170                if(debug)UndefinedImpl.debugCascadedAccess(ThreadLocalPageContext.get(),arg.getTypeAsString(), key);
171                return arg.setEL(key,value);
172        }
173                
174                if(debug)UndefinedImpl.debugCascadedAccess(ThreadLocalPageContext.get(),var.getTypeAsString(), key);
175                return var.setEL(key,value);
176        }
177
178        @Override
179        public Collection duplicate(boolean deepCopy) {
180                return new ClosureScope(ThreadLocalPageContext.get(),(Argument)Duplicator.duplicate(arg,deepCopy), (Local)Duplicator.duplicate(local,deepCopy), (Variables)Duplicator.duplicate(var,deepCopy));
181        }
182
183        @Override
184        public boolean containsKey(Key key) {
185                return get(key,NULL)!=NULL;
186        }
187
188        @Override
189        public Iterator<Collection.Key> keyIterator() {
190                return var.keyIterator();
191        }
192    
193    @Override
194        public Iterator<String> keysAsStringIterator() {
195        return var.keysAsStringIterator();
196    }
197        
198        @Override
199        public Iterator<Entry<Key, Object>> entryIterator() {
200                return var.entryIterator();
201        }
202        
203        @Override
204        public Iterator<Object> valueIterator() {
205                return var.valueIterator();
206        }
207        
208        @Override
209        public void setBind(boolean bind) {}
210
211        @Override
212        public boolean isBind() {
213                return true;
214        }
215        
216        @Override
217        public DumpData toDumpData(PageContext pageContext, int maxlevel,
218                        DumpProperties properties) {
219                
220                DumpTable dt= (DumpTable) super.toDumpData(pageContext, maxlevel, properties);
221                dt.setTitle("Closure Variable Scope");
222                return dt;
223        }
224
225
226}