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.commons.collection;
020
021import java.io.Serializable;
022import java.util.Collection;
023import java.util.HashSet;
024import java.util.Iterator;
025import java.util.Map;
026import java.util.Set;
027
028import lucee.runtime.exp.ExpressionException;
029import lucee.runtime.exp.PageException;
030
031public class MapProWrapper<K, V> implements MapPro<K, V>,Serializable {
032
033        private final V NULL;
034        private Map<K, V> map;
035
036        public MapProWrapper(Map<K, V> map,V NULL){
037                this.map=map;
038                this.NULL=NULL;
039        }
040        
041        @Override
042        public void clear() {
043                map.clear();
044        }
045
046        @Override
047        public boolean containsKey(Object key) {
048                return map.containsKey(key);
049        }
050
051        @Override
052        public boolean containsValue(Object value) {
053                if(value==null)value=NULL;
054                return map.containsValue(value);
055        }
056
057        @Override
058        public Set<java.util.Map.Entry<K, V>> entrySet() {
059                Set<Entry<K, V>> src = map.entrySet();
060                Iterator<Entry<K, V>> it = src.iterator();
061                Entry<K, V> e;
062                while(it.hasNext()){
063                        e = it.next();
064                        if(e.getValue()==NULL) e.setValue(null);
065                }
066                return src;
067        }
068
069        @Override
070        public V get(Object key) {
071                V v = map.get(key);
072                if(v==NULL) return null;
073                return v;
074        }
075
076        @Override
077        public V g(K key, V defaultValue) {
078                V v = map.get(key);
079                if(v==NULL) return null;
080                if(v==null) return defaultValue;
081                return v;
082        }
083
084        @Override
085        public V g(K key) throws PageException {
086                V v = map.get(key);
087                if(v==NULL) return null;
088                if(v==null) throw invalidKey(this,key,false);
089                return v;
090        }
091
092        @Override
093        public V r(K key, V defaultValue) {
094                V v = map.remove(key);
095                if(v==NULL) return null;
096                if(v==null) return defaultValue;
097                return v;
098        }
099
100        @Override
101        public V r(K key) throws PageException {
102                V v = map.get(key);
103                if(v==NULL) return null;
104                if(v==null) throw invalidKey(this,key,true);
105                return v;
106        }
107        
108        private ExpressionException invalidKey(Map<K,V> map,K key, boolean remove) {
109
110                StringBuilder sb=new StringBuilder();
111                Iterator<K> it = map.keySet().iterator();
112                K k;
113                while(it.hasNext()){
114                        k = it.next();
115                        if(sb.length()>0)sb.append(',');
116                        sb.append(k.toString());
117                }
118
119                return new ExpressionException(
120                                (remove?
121                                                "cannot remove key ["+key+"] from struct, key doesn't exist":
122                                                "key [" + key + "] doesn't exist") +
123                                " (existing keys:" + sb.toString() + ")" );
124        }
125        
126        @Override
127        public boolean isEmpty() {
128                return map.isEmpty();
129        }
130
131        @Override
132        public Set<K> keySet() {
133                return map.keySet();
134        }
135
136        @Override
137        public V put(K key, V value) {
138                V old;
139                if(value==null) old=map.put(key, NULL);
140                else old=map.put(key, value);
141                
142                if(old==NULL) return null;
143                return old;
144        }
145
146        @Override
147        public void putAll(Map<? extends K, ? extends V> m) {
148                for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
149            put(e.getKey(), e.getValue());
150                }
151        }
152
153        @Override
154        public V remove(Object key) {
155                return map.remove(key);
156        }
157
158        @Override
159        public int size() {
160                return map.size();
161        }
162
163        @Override
164        public Collection<V> values() {
165                Collection<V> src = map.values();
166                Set<V> trg = new HashSet<V>();
167                Iterator<V> it = src.iterator();
168                V v;
169                while(it.hasNext()){
170                        v = it.next();
171                        if(v==NULL) trg.add(null);
172                        else trg.add(v);
173                }
174                return trg;
175        }
176
177        @Override
178        public boolean equals(Object arg0) {
179                return map.equals(arg0);
180        }
181
182        @Override
183        public int hashCode() {
184                return map.hashCode();
185        }
186
187        @Override
188        public String toString() {
189                return map.toString();
190        }
191        
192        public Map<K, V> getMap(){
193                return map;
194        }
195}