/*
* Copyright © 2010-2011 Rebecca G. Bettencourt / Kreative Software
* <p>
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* <a href="http://www.mozilla.org/MPL/">http://www.mozilla.org/MPL/</a>
* <p>
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
* <p>
* Alternatively, the contents of this file may be used under the terms
* of the GNU Lesser General Public License (the "LGPL License"), in which
* case the provisions of LGPL License are applicable instead of those
* above. If you wish to allow use of your version of this file only
* under the terms of the LGPL License and not to allow others to use
* your version of this file under the MPL, indicate your decision by
* deleting the provisions above and replace them with the notice and
* other provisions required by the LGPL License. If you do not delete
* the provisions above, a recipient may use your version of this file
* under either the MPL or the LGPL License.
* @since KSFL 1.2
* @author Rebecca G. Bettencourt, Kreative Software
*/
package com.kreative.binpack;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
public class MapStack<K,V> implements Map<K,V> {
private List<Map<K,V>> stack = new Vector<Map<K,V>>();
public void popAll() {
stack.clear();
}
public Map<K,V> pop() {
return stack.isEmpty() ? null : stack.remove(0);
}
public Map<K,V> peek() {
return stack.isEmpty() ? null : stack.get(0);
}
public void push(Map<K,V> map) {
stack.add(0, map);
}
public int depth() {
return stack.size();
}
public int size() {
Set<K> tmp = new HashSet<K>();
for (Map<K,V> map : stack) {
tmp.addAll(map.keySet());
}
return tmp.size();
}
public boolean isEmpty() {
for (Map<K,V> map : stack) {
if (!map.isEmpty()) {
return false;
}
}
return true;
}
public boolean containsKey(Object key) {
for (Map<K,V> map : stack) {
if (map.containsKey(key)) {
return true;
}
}
return false;
}
public boolean containsValue(Object value) {
for (Map<K,V> map : stack) {
if (map.containsValue(value)) {
return true;
}
}
return false;
}
public V get(Object key) {
for (Map<K,V> map : stack) {
if (map.containsKey(key)) {
return map.get(key);
}
}
return null;
}
public V put(K key, V value) {
return stack.get(0).put(key, value);
}
public V remove(Object key) {
for (Map<K,V> map : stack) {
if (map.containsKey(key)) {
return map.remove(key);
}
}
return null;
}
public void putAll(Map<? extends K, ? extends V> t) {
stack.get(0).putAll(t);
}
public void clear() {
for (Map<K,V> map : stack) {
map.clear();
}
}
public Set<K> keySet() {
return new Set<K>() {
public int size() {
return MapStack.this.size();
}
public boolean isEmpty() {
return MapStack.this.isEmpty();
}
public boolean contains(Object o) {
return MapStack.this.containsKey(o);
}
public Iterator<K> iterator() {
LinkedHashSet<K> tmp = new LinkedHashSet<K>();
for (Map<K,V> map : stack) {
tmp.addAll(map.keySet());
}
final Iterator<K> tmpi = tmp.iterator();
return new Iterator<K>() {
K last = null;
public boolean hasNext() {
return tmpi.hasNext();
}
public K next() {
return last = tmpi.next();
}
public void remove() {
MapStack.this.remove(last);
}
};
}
public Object[] toArray() {
LinkedHashSet<K> tmp = new LinkedHashSet<K>();
for (Map<K,V> map : stack) {
tmp.addAll(map.keySet());
}
return tmp.toArray();
}
public <T> T[] toArray(T[] a) {
LinkedHashSet<K> tmp = new LinkedHashSet<K>();
for (Map<K,V> map : stack) {
tmp.addAll(map.keySet());
}
return tmp.toArray(a);
}
public boolean add(K o) {
throw new UnsupportedOperationException();
}
public boolean remove(Object o) {
for (Map<K,V> map : stack) {
if (map.containsKey(o)) {
map.remove(o);
return true;
}
}
return false;
}
public boolean containsAll(Collection<?> c) {
for (Object o : c) {
if (!MapStack.this.containsKey(o)) {
return false;
}
}
return true;
}
public boolean addAll(Collection<? extends K> c) {
throw new UnsupportedOperationException();
}
public boolean retainAll(Collection<?> c) {
boolean ret = false;
Set<K> tmp = new HashSet<K>();
for (Map<K,V> map : stack) {
tmp.addAll(map.keySet());
}
tmp.removeAll(c);
for (Map<K,V> map : stack) {
for (K key : tmp) {
if (map.containsKey(key)) {
map.remove(key);
ret = true;
}
}
}
return ret;
}
public boolean removeAll(Collection<?> c) {
boolean ret = false;
for (Object o : c) {
for (Map<K,V> map : stack) {
if (map.containsKey(o)) {
map.remove(o);
ret = true;
break;
}
}
}
return ret;
}
public void clear() {
MapStack.this.clear();
}
};
}
public Collection<V> values() {
return new Collection<V>() {
public int size() {
return MapStack.this.size();
}
public boolean isEmpty() {
return MapStack.this.isEmpty();
}
public boolean contains(Object o) {
return MapStack.this.containsValue(o);
}
public Iterator<V> iterator() {
LinkedHashSet<K> tmp = new LinkedHashSet<K>();
for (Map<K,V> map : stack) {
tmp.addAll(map.keySet());
}
final Iterator<K> tmpi = tmp.iterator();
return new Iterator<V>() {
K last = null;
public boolean hasNext() {
return tmpi.hasNext();
}
public V next() {
return MapStack.this.get(last = tmpi.next());
}
public void remove() {
MapStack.this.remove(last);
}
};
}
public Object[] toArray() {
LinkedHashSet<K> tmp = new LinkedHashSet<K>();
for (Map<K,V> map : stack) {
tmp.addAll(map.keySet());
}
List<V> tmp2 = new ArrayList<V>();
for (K key : tmp) {
tmp2.add(MapStack.this.get(key));
}
return tmp2.toArray();
}
public <T> T[] toArray(T[] a) {
LinkedHashSet<K> tmp = new LinkedHashSet<K>();
for (Map<K,V> map : stack) {
tmp.addAll(map.keySet());
}
List<V> tmp2 = new ArrayList<V>();
for (K key : tmp) {
tmp2.add(MapStack.this.get(key));
}
return tmp2.toArray(a);
}
public boolean add(V o) {
throw new UnsupportedOperationException();
}
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
public boolean containsAll(Collection<?> c) {
for (Object o : c) {
if (!MapStack.this.containsValue(o)) {
return false;
}
}
return true;
}
public boolean addAll(Collection<? extends V> c) {
throw new UnsupportedOperationException();
}
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
public boolean retainAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
public void clear() {
MapStack.this.clear();
}
};
}
public Set<Map.Entry<K,V>> entrySet() {
return new Set<Map.Entry<K,V>>() {
public int size() {
return MapStack.this.size();
}
public boolean isEmpty() {
return MapStack.this.isEmpty();
}
public boolean contains(Object o) {
if (o instanceof Map.Entry) {
Object key = ((Map.Entry<?,?>)o).getKey();
Object value = ((Map.Entry<?,?>)o).getValue();
for (Map<K,V> map : stack) {
if (map.containsKey(key) && map.get(key).equals(value)) {
return true;
}
}
}
return false;
}
public Iterator<Map.Entry<K,V>> iterator() {
LinkedHashSet<K> tmp = new LinkedHashSet<K>();
for (Map<K,V> map : stack) {
tmp.addAll(map.keySet());
}
final Iterator<K> tmpi = tmp.iterator();
return new Iterator<Map.Entry<K,V>>() {
K last = null;
public boolean hasNext() {
return tmpi.hasNext();
}
public Map.Entry<K,V> next() {
final K key = last = tmpi.next();
return new Map.Entry<K,V>() {
public K getKey() {
return key;
}
public V getValue() {
return MapStack.this.get(key);
}
public V setValue(V value) {
V ret = MapStack.this.get(key);
MapStack.this.put(key, value);
return ret;
}
public boolean equals(Object o) {
if (o instanceof Map.Entry) {
Map.Entry<?,?> other = (Map.Entry<?,?>)o;
return (this.getKey().equals(other.getKey()) && this.getValue().equals(other.getValue()));
} else {
return false;
}
}
public int hashCode() {
return this.getKey().hashCode() ^ this.getValue().hashCode();
}
};
}
public void remove() {
MapStack.this.remove(last);
}
};
}
public Object[] toArray() {
LinkedHashSet<K> tmp = new LinkedHashSet<K>();
for (Map<K,V> map : stack) {
tmp.addAll(map.keySet());
}
List<Map.Entry<K,V>> tmp2 = new ArrayList<Map.Entry<K,V>>();
for (final K key : tmp) {
tmp2.add(new Map.Entry<K,V>(){
public K getKey() {
return key;
}
public V getValue() {
return MapStack.this.get(key);
}
public V setValue(V value) {
V ret = MapStack.this.get(key);
MapStack.this.put(key, value);
return ret;
}
public boolean equals(Object o) {
if (o instanceof Map.Entry) {
Map.Entry<?,?> other = (Map.Entry<?,?>)o;
return (this.getKey().equals(other.getKey()) && this.getValue().equals(other.getValue()));
} else {
return false;
}
}
public int hashCode() {
return this.getKey().hashCode() ^ this.getValue().hashCode();
}
});
}
return tmp2.toArray();
}
public <T> T[] toArray(T[] a) {
LinkedHashSet<K> tmp = new LinkedHashSet<K>();
for (Map<K,V> map : stack) {
tmp.addAll(map.keySet());
}
List<Map.Entry<K,V>> tmp2 = new ArrayList<Map.Entry<K,V>>();
for (final K key : tmp) {
tmp2.add(new Map.Entry<K,V>(){
public K getKey() {
return key;
}
public V getValue() {
return MapStack.this.get(key);
}
public V setValue(V value) {
V ret = MapStack.this.get(key);
MapStack.this.put(key, value);
return ret;
}
public boolean equals(Object o) {
if (o instanceof Map.Entry) {
Map.Entry<?,?> other = (Map.Entry<?,?>)o;
return (this.getKey().equals(other.getKey()) && this.getValue().equals(other.getValue()));
} else {
return false;
}
}
public int hashCode() {
return this.getKey().hashCode() ^ this.getValue().hashCode();
}
});
}
return tmp2.toArray(a);
}
public boolean add(Map.Entry<K,V> o) {
MapStack.this.put(o.getKey(), o.getValue());
return true;
}
public boolean remove(Object o) {
if (o instanceof Map.Entry) {
Object key = ((Map.Entry<?,?>)o).getKey();
Object value = ((Map.Entry<?,?>)o).getValue();
for (Map<K,V> map : stack) {
if (map.containsKey(key) && map.get(key).equals(value)) {
map.remove(key);
return true;
}
}
}
return false;
}
public boolean containsAll(Collection<?> c) {
for (Object o : c) {
if (o instanceof Map.Entry) {
boolean ret = false;
Object key = ((Map.Entry<?,?>)o).getKey();
Object value = ((Map.Entry<?,?>)o).getValue();
for (Map<K,V> map : stack) {
if (map.containsKey(key) && map.get(key).equals(value)) {
ret = true;
break;
}
}
if (!ret) return false;
} else {
return false;
}
}
return true;
}
public boolean addAll(Collection<? extends Map.Entry<K,V>> c) {
for (Map.Entry<K,V> o : c) {
MapStack.this.put(o.getKey(), o.getValue());
}
return true;
}
public boolean retainAll(Collection<?> c) {
boolean ret = false;
LinkedHashSet<K> tmp = new LinkedHashSet<K>();
for (Map<K,V> map : stack) {
tmp.addAll(map.keySet());
}
List<Map.Entry<K,V>> tmp2 = new ArrayList<Map.Entry<K,V>>();
for (final K key : tmp) {
tmp2.add(new Map.Entry<K,V>(){
public K getKey() {
return key;
}
public V getValue() {
return MapStack.this.get(key);
}
public V setValue(V value) {
V ret = MapStack.this.get(key);
MapStack.this.put(key, value);
return ret;
}
public boolean equals(Object o) {
if (o instanceof Map.Entry) {
Map.Entry<?,?> other = (Map.Entry<?,?>)o;
return (this.getKey().equals(other.getKey()) && this.getValue().equals(other.getValue()));
} else {
return false;
}
}
public int hashCode() {
return this.getKey().hashCode() ^ this.getValue().hashCode();
}
});
}
tmp2.removeAll(c);
for (Map<K,V> map : stack) {
for (Map.Entry<K,V> e : tmp2) {
if (map.containsKey(e.getKey()) && map.get(e.getKey()).equals(e.getValue())) {
map.remove(e.getKey());
ret = true;
}
}
}
return ret;
}
public boolean removeAll(Collection<?> c) {
boolean ret = false;
for (Object o : c) {
if (o instanceof Map.Entry) {
Object key = ((Map.Entry<?,?>)o).getKey();
Object value = ((Map.Entry<?,?>)o).getValue();
for (Map<K,V> map : stack) {
if (map.containsKey(key) && map.get(key).equals(value)) {
map.remove(key);
ret = true;
break;
}
}
}
}
return ret;
}
public void clear() {
MapStack.this.clear();
}
};
}
}