package org.psjava.ds.map;

import java.util.Iterator;

import org.psjava.algo.math.PairHash;
import org.psjava.util.AssertStatus;
import org.psjava.util.ConvertedDataIterator;
import org.psjava.util.DataConverter;
import org.psjava.util.EqualityTester;
import org.psjava.util.StrictEqualityTester;

public class MutableMapUsingJavaMap {

	public static <K, V> MutableMap<K, V> create(final java.util.Map<K, V> map) {
		return new MutableMap<K, V>() {

			boolean nullValuePut = false;

			@Override
			public boolean containsKey(K key) {
				return map.containsKey(key);
			}

			@Override
			public V get(K key) {
				V r = map.get(key);
				if (r != null) {
					return r;
				} else { // because java map's get returns null even if value is null.
					AssertStatus.assertTrue(nullValuePut && map.containsKey(key), "the key in not int the map");
					return null;
				}
			}

			@Override
			public V get(K key, V def) {
				if (!containsKey(key))
					return def;
				return map.get(key);
			}

			@Override
			public void put(K key, V value) {
				if (value == null)
					nullValuePut = true;
				map.put(key, value);
			}

			@Override
			public void clear() {
				map.clear();
			}

			@Override
			public boolean isEmpty() {
				return map.isEmpty();
			}

			@Override
			public Iterator<MapEntry<K, V>> iterator() {
				return ConvertedDataIterator.create(map.entrySet().iterator(), new DataConverter<java.util.Map.Entry<K, V>, MapEntry<K, V>>() {
					@Override
					public MapEntry<K, V> convert(java.util.Map.Entry<K, V> e) {
						return new EntryWrapper<K, V>(e);
					}
				});
			}

			@Override
			public int size() {
				return map.size();
			}

			@Override
			public void remove(K key) {
				map.remove(key);
			}

			@Override
			public String toString() {
				return map.toString();
			}

		};
	}

	private static class EntryWrapper<K, V> implements MapEntry<K, V>, EqualityTester<EntryWrapper<K, V>> {
		private java.util.Map.Entry<K, V> e;

		private EntryWrapper(java.util.Map.Entry<K, V> e) {
			this.e = e;
		}

		@Override
		public K getKey() {
			return e.getKey();
		}

		@Override
		public V getValue() {
			return e.getValue();
		}

		@Override
		public boolean equals(Object obj) {
			return StrictEqualityTester.areEqual(this, obj, this);
		}

		@Override
		public boolean areEqual(EntryWrapper<K, V> o1, EntryWrapper<K, V> o2) {
			return o1.getKey().equals(o2.getKey()) && o1.getValue().equals(o2.getValue());
		}

		@Override
		public int hashCode() {
			return PairHash.hash(getKey().hashCode(), getValue().hashCode());
		}
	}

}

@@ -53,46 +53,8 @@
 r;%0A%0A
-import org.psjava.algo.math.PairHash;%0A
 impo
@@ -205,24 +205,70 @@
 lityTester;%0A
+import org.psjava.util.OrderFreeIterableHash;%0A
 import org.p
@@ -340,16 +340,40 @@
 aMap %7B%0A%0A
+%09// TODO rename to wrap%0A
 %09public 
@@ -1837,16 +1837,389 @@
 ;%0A%09%09%09%7D%0A%0A
+%09%09%09@Override%0A%09%09%09public boolean equals(Object obj) %7B%0A%09%09%09%09return StrictEqualityTester.areEqual(this, obj, new EqualityTester%3CMap%3CK, V%3E%3E() %7B%0A%09%09%09%09%09@Override%0A%09%09%09%09%09public boolean areEqual(Map%3CK, V%3E m1, Map%3CK, V%3E m2) %7B%0A%09%09%09%09%09%09return MapEqualityTester.areEqual(m1, m2);%0A%09%09%09%09%09%7D%0A%09%09%09%09%7D);%0A%09%09%09%7D%0A%0A%09%09%09@Override%0A%09%09%09public int hashCode() %7B%0A%09%09%09%09return OrderFreeIterableHash.hash(this);%0A%09%09%09%7D%0A%0A
 %09%09%7D;%0A%09%7D%0A
@@ -2777,77 +2777,41 @@
 urn 
-o1.getKey().equals(o2.getKey()) && o1.getValue().equals(o2.getValue()
+MapEntryEqualityTester.are(o1, o2
 );%0A%09
@@ -2866,12 +2866,16 @@
 urn 
-Pair
+MapEntry
 Hash
@@ -2884,50 +2884,12 @@
 ash(
-getKey().hashCode(), getValue().hashCode()
+this
 );%0A%09

fix equality check bug of MutableMapUsingJavaMap