package com.hammurapi.reasoning.impl;

import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import com.hammurapi.reasoning.Handle;
import com.hammurapi.reasoning.ReasoningException;

public class HandleCollection<E> implements Collection<E>, ReadWriteLock {
	
	protected Collection<Handle<E>> handleCollection;
	protected KnowledgeBase<E> knowledgeBase;


	public HandleCollection(KnowledgeBase<E> kb, Collection<Handle<E>> handleCollection) {		
		this.knowledgeBase = kb;
		this.handleCollection = handleCollection;
	}


	public boolean add(E e) {
		try {
			return handleCollection.add(knowledgeBase.put(e));
		} catch (ReasoningException ex) {
			throw new RuntimeReasoningException(ex);
		}
	}


	public boolean addAll(Collection<? extends E> c) {
		boolean ret = false;
		for (E e: c) {
			if (add(e)) {
				ret = true;
			}
		}
		return ret;
	}


	public void clear() {
		handleCollection.clear();
	}


	public boolean contains(Object o) {
		Handle<E> handle = knowledgeBase.getHandle(o);
		return handle==null ? false : handleCollection.contains(handle);
	}


	public boolean containsAll(Collection<?> c) {
		for (Object o: c) {
			if (!contains(o)) {
				return false;
			}
		}
		return true;
	}


	// TODO - implement equals and hash code correctly 
//	public boolean equals(Object o) {
//		return handleCollection.equals(o);
//	}
//
//
//	public int hashCode() {
//		return handleCollection.hashCode();
//	}


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


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

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

			@SuppressWarnings("unchecked")
			@Override
			public E next() {
				Handle hNext = master.next();
				return ((HandleImpl<E>) hNext).get();
			}

			@Override
			public void remove() {
				master.remove();				
			}
			
		};
	}


	public boolean remove(Object o) {
		Handle<E> handle = knowledgeBase.getHandle(o);
		return handle==null ? false : handleCollection.remove(handle);
	}


	public boolean removeAll(Collection<?> c) {
		boolean ret = false;
		for (Object e: c) {
			if (remove(e)) {
				ret = true;
			}
		}
		return ret;
	}


	public boolean retainAll(Collection<?> c) {
		boolean ret = true;
		Iterator<E> it = iterator();
		while (it.hasNext()) {
			E next = it.next();
			if (!c.contains(next)) {
				ret = true;
				it.remove();
			}
		}
		return ret;
	}


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

	public Object[] toArray() {
		Object[] ret = new Object[size()];
		Iterator<E> it = iterator();
		for (int i=0; it.hasNext(); ++i) {
			ret[i] = it.next();
		}
		return ret;
	}


	@SuppressWarnings("unchecked")
	public <T> T[] toArray(T[] a) {
		T[] ret = a.length>=size() ? a : (T[]) Array.newInstance(a.getClass().getComponentType(), size());
		Iterator<E> it = iterator();
		for (int i=0; it.hasNext(); ++i) {
			ret[i] = (T) it.next();
		}
		return ret;
	}

	private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

	@Override
	public Lock readLock() {
		return rwLock.readLock();
	}


	@Override
	public Lock writeLock() {
		return rwLock.writeLock();
	}
	
	
}
