package com.floreysoft.jmte;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
/**
* A map implementation that serves as the internal model.
* <p>
* Special feature of this implementation are that you can open and close scopes
* of local variables.
* </p>
*
*/
public class ScopedMap implements Map<String, Object> {
private final Map<String, Object> rawModel;
private final Stack<Map<String, Object>> scopes = new Stack<Map<String, Object>>();
public void clear() {
throw new UnsupportedOperationException();
}
public boolean containsKey(Object key) {
return get(key) != null;
}
public boolean containsValue(Object value) {
throw new UnsupportedOperationException();
}
public Set<Entry<String, Object>> entrySet() {
throw new UnsupportedOperationException();
}
public Object get(Object key) {
for (int i = scopes.size() - 1; i >= 0; i--) {
Map<String, Object> map = scopes.get(i);
Object value = map.get(key);
if (value != null) {
return value;
}
}
return rawModel.get(key);
}
public boolean isEmpty() {
throw new UnsupportedOperationException();
}
public Set<String> keySet() {
throw new UnsupportedOperationException();
}
public Object put(String key, Object value) {
return getCurrentScope().put(key, value);
}
public void putAll(Map<? extends String, ? extends Object> m) {
throw new UnsupportedOperationException();
}
public Object remove(Object key) {
throw new UnsupportedOperationException();
}
public int size() {
throw new UnsupportedOperationException();
}
public Collection<Object> values() {
throw new UnsupportedOperationException();
}
/**
* Creates a new scoped map.
*
* @param rawModel
* the raw model backing this scoped map
*/
public ScopedMap(Map<String, Object> rawModel) {
if (rawModel == null) {
throw new IllegalArgumentException("Model must not be null");
}
this.rawModel = rawModel;
}
/**
* Gets the raw model backing this scoped map
*
* @return the raw model backing this scoped map
*/
public Map<String, Object> getRawModel() {
return rawModel;
}
/**
* Checks if a given variable is local.
*/
public boolean isLocal(String variable) {
return containsKey(variable) && !rawModel.containsKey(variable);
}
/**
* Creates a new local scope and sets it as the current one.
*/
public void enterScope() {
scopes.push(createScope());
}
/**
* Discards the current local scope.
*/
public void exitScope() {
if (scopes.size() == 0) {
throw new IllegalStateException("There is no state to exit");
}
scopes.pop();
}
protected Map<String, Object> getCurrentScope() {
if (scopes.size() > 0) {
return scopes.peek();
} else {
return rawModel;
}
}
protected Map<String, Object> createScope() {
return new HashMap<String, Object>();
}
@Override
public String toString() {
return rawModel.toString() + scopes.toString();
}
}