package com.hammurapi.common;

import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicBoolean;

public class FreezeableCollection<E> implements Collection<E> {
	
	private Collection<E> master;
	private AtomicBoolean freezed = new AtomicBoolean(false);

	public FreezeableCollection(Collection<E> master) {
		this.master = master;
	}

	public int size() {
		return master.size();
	}

	public boolean isEmpty() {
		return master.isEmpty();
	}

	public boolean contains(Object o) {
		return master.contains(o);
	}

	public Iterator<E> iterator() {
		return new Iterator<E>() {
			Iterator<E> masterIterator = master.iterator();

			@Override
			public boolean hasNext() {
				return masterIterator.hasNext();
			}

			@Override
			public E next() {
				return masterIterator.next();
			}

			@Override
			public void remove() {
				checkFrozen();
				masterIterator.remove();
			}
			
		};
		
	}

	public Object[] toArray() {
		return master.toArray();
	}

	public <T> T[] toArray(T[] a) {
		return master.toArray(a);
	}

	public boolean add(E e) {
		checkFrozen();
		return master.add(e);
	}

	public boolean remove(Object o) {
		checkFrozen();
		return master.remove(o);
	}

	public boolean containsAll(Collection<?> c) {
		return master.containsAll(c);
	}

	public boolean addAll(Collection<? extends E> c) {
		checkFrozen();
		return master.addAll(c);
	}

	public boolean removeAll(Collection<?> c) {
		checkFrozen();
		return master.removeAll(c);
	}

	public boolean retainAll(Collection<?> c) {
		checkFrozen();
		return master.retainAll(c);
	}

	public void clear() {
		checkFrozen();
		master.clear();
	}

	public boolean equals(Object o) {
		return master.equals(o);
	}

	public int hashCode() {
		return master.hashCode();
	}
	
	/**
	 * Freezes collection making it unmodifiable.
	 */
	public void freeze() {
		freezed.set(true);
	}

	private void checkFrozen() {
		if (freezed.get()) {
			IllegalStateException th = new IllegalStateException("Collection is frozen, no modifications are allowed");
			th.printStackTrace();
			throw th;
		}
	}

}
