package org.jivesoftware.util;

import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collections;
import java.util.Set;

public class Immutable {
	
	/**
	 * Wraps an existing {@link Collection} to provide read-only access to its contents.
	 */
	public static class Collection<V> extends java.util.AbstractCollection<V> {

		private java.util.Collection<V> delegate;
		
		public Collection(java.util.Collection<V> delegate) {
			this.delegate = delegate;
		}

		@Override
		public Iterator<V> iterator() {
			return new Iterator<V>(delegate.iterator());
		}

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

	/**
	 * Read-only {@link Iterator} prevents removal of objects
	 */
	public static class Iterator<V> implements java.util.Iterator<V> {

		private java.util.Iterator<V> delegate;
		
		public Iterator(java.util.Iterator<V> delegate) {
			this.delegate = delegate;
		}
		public boolean hasNext() {
			return delegate.hasNext();
		}

		public V next() {
			return delegate.next();
		}

		public void remove() {
			throw new UnsupportedOperationException();
		}
	}
	
	/**
	 * Wraps a {@link Map} to provide read-only access to its elements.
	 */
	public static class Map<K,V> extends AbstractMap<K,V> {

		private java.util.Map<K,V> backingMap;
		
		/**
		 * Use this constructor to provide a pre-populated map that will be
		 * made read-only via this wrapper class
		 * @param backingMap
		 */
		public Map(java.util.Map<K,V> backingMap) {
			this.backingMap = backingMap;
		}
		/**
		 * Default constructor (empty map)
		 */
		public Map() { }

		@Override
		public Set<Map.Entry<K,V>> entrySet() {
			if (backingMap == null) {
				return Collections.emptySet();
			} else {
				return new AbstractSet<Map.Entry<K,V>>() {
					public Iterator<Map.Entry<K,V>> iterator() {
						return new Iterator<Entry<K, V>>(backingMap.entrySet().iterator());
					}
					public int size() {
						return backingMap.size();
					}
				};
			}
		}
	}
	
}