package org.ow2.chameleon.rose.util;

import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * TODO doc
 * @author barjo
 *
 * @param <T>
 * @param <E>
 */
public class ConcurrentMapOfSet<T, E> {

	private final Map<T, Collection<E>> innermap;

	private final ReentrantReadWriteLock rwlock;

	public ConcurrentMapOfSet() {
		innermap = new ConcurrentHashMap<T, Collection<E>>();
		rwlock = new ReentrantReadWriteLock();
	}

	public int size() {
		rwlock.readLock().lock();
		try {
			return innermap.size();
		} finally {
			rwlock.readLock().unlock();
		}
	}

	public boolean isEmpty() {
		rwlock.readLock().lock();
		try {
			return innermap.isEmpty();
		} finally {
			rwlock.readLock().unlock();
		}
	}

	public boolean containsKey(Object key) {
		rwlock.readLock().lock();
		try {
			return innermap.containsKey(key);
		} finally {
			rwlock.readLock().unlock();
		}
	}

	public Collection<E> remove(Object key) {
		rwlock.writeLock().lock();
		try {
			return innermap.remove(key);
		} finally {
			rwlock.writeLock().unlock();
		}
	}

	public void clear() {
		rwlock.writeLock().lock();
		try {
			innermap.clear();
		} finally {
			rwlock.writeLock().unlock();
		}
	}

	/**
	 * 
	 * @param key
	 * @param value
	 * @return true if the mapOfSet change as the result of the call.
	 */
	public boolean add(T key, E value) {
		boolean retvalue;

		rwlock.writeLock().lock();
		try {
			if (innermap.containsKey(key)) {
				retvalue = innermap.get(key).add(value);
			} else {
				Collection<E> coll = new HashSet<E>();
				coll.add(value);
				innermap.put(key, coll);
				retvalue = true;
			}
		} finally {
			rwlock.writeLock().unlock();
		}

		return retvalue;
	}

	/**
	 * @param key
	 * @param elem
	 * @return true if the removed element was the last of the collection.
	 */
	public boolean remove(T key, E elem) {
		boolean retvalue = false;

		rwlock.writeLock().lock();
		try {

			if (innermap.containsKey(key)) {
				Collection<E> coll = innermap.get(key);
				coll.remove(elem);

				if (coll.isEmpty()) {
					innermap.remove(key);
					retvalue = true;
				}
			} 
			
		} finally {
			rwlock.writeLock().unlock();
		}

		return retvalue;
	}

	public E getElem(T key) {
		rwlock.readLock().lock();
		try {
			if (innermap.containsKey(key)) {
				return innermap.get(key).iterator().next();
			} else {
				return null;
			}
		} finally {
			rwlock.readLock().unlock();
		}
	}
	
	
	/**
	 * @return a view of the keys.
	 */
	public Set<T> keySet(){
		rwlock.readLock().lock();
		try {
			return innermap.keySet();
		} finally{
			rwlock.readLock().unlock();
		}
	}

}

@@ -30,32 +30,39 @@
 e.util;%0A%0Aimport 
+static 
 java.util.Collec
@@ -65,16 +65,89 @@
 llection
+s.unmodifiableSet;%0A%0Aimport java.util.Collection;%0Aimport java.util.HashMap
 ;%0Aimport
@@ -214,55 +214,8 @@
 et;%0A
-import java.util.concurrent.ConcurrentHashMap;%0A
 impo
@@ -285,16 +285,90 @@
 ODO doc%0A
+ * XXX Not really efficient, see if there is something similar in Guava ?%0A
  * @auth
@@ -578,16 +578,16 @@
 Set() %7B%0A
+
 %09%09innerm
@@ -595,26 +595,16 @@
 p = new 
-Concurrent
 HashMap%3C
@@ -2749,32 +2749,48 @@
 try %7B%0A%09%09%09return 
+unmodifiableSet(
 innermap.keySet(
@@ -2790,16 +2790,17 @@
 keySet()
+)
 ;%0A%09%09%7D fi

Remove useless local ConcurrentHashMap.