/*
 * Copyright 2006 Takahiro Nakamura.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package woolpack.utils;

import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

class InverseMap<K, V> extends AbstractMap<K, V> {
	private final Map<V, K> map;
	
	InverseMap(final Map<V, K> map) {
		super();
		this.map = new InjectiveMap<V, K>(map);
	}
	
	public V put(final K key, final V val) {
		final V before = get(key);
		map.put(val, key);
		return before;
	}

	@Override
	public Set<java.util.Map.Entry<K, V>> entrySet() {
		return new AbstractSet<Entry<K, V>>() {
			@Override
			public int size() {
				return map.size();
			}

			@Override
			public Iterator<Entry<K, V>> iterator() {
				final Iterator<Entry<V, K>> it = map.entrySet().iterator();
				return new Iterator<Entry<K, V>>() {
					public void remove() {
						it.remove();
					}

					public boolean hasNext() {
						return it.hasNext();
					}

					public Entry<K, V> next() {
						final Entry<V, K> entry = it.next();
						return new Entry<K, V>() {
							public K getKey() {
								return entry.getValue();
							}

							public V getValue() {
								return entry.getKey();
							}

							public V setValue(final V value) {
								throw new UnsupportedOperationException();
							}

							@Override
							public boolean equals(final Object obj) {
								if (this == obj) {
									return true;
								}
								if (obj == null) {
									return false;
								}
								if (getClass() != obj.getClass()) {
									return false;
								}
								final Entry other = (Entry) obj;
								if (getKey() == null) {
									if (other.getKey() != null) {
										return false;
									}
								} else if (!getKey().equals(other.getKey())) {
									return false;
								}
								if (getValue() == null) {
									if (other.getValue() != null) {
										return false;
									}
								} else if (!getValue().equals(other.getValue())) {
									return false;
								}
								return true;
							}

							@Override
							public int hashCode() {
								final int PRIME = 31;
								int result = 1;
								result = PRIME * result + ((getKey() == null) ? 0 : getKey().hashCode());
								result = PRIME * result + ((getValue() == null) ? 0 : getValue().hashCode());
								return result;
							}
						};
					}
				};
			}
		};
	}
}
