package com.hammurapi.reasoning.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.ListIterator;

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

public class HandleList<E> extends HandleCollection<E> implements List<E> {

	public HandleList(KnowledgeBase<E> kb, List<Handle<E>> handleCollection) {
		super(kb, handleCollection);
	}

	@Override
	public void add(int index, E element) {
		try {
			((List<Handle<E>>) handleCollection).add(index, knowledgeBase.put(element));
		} catch (ReasoningException e) {
			throw new RuntimeReasoningException(e);
		}
	}

	@Override
	public boolean addAll(int index, Collection<? extends E> c) {
		ArrayList<Handle<E>> hc = new ArrayList<Handle<E>>();
		for (E e: c) {
			try {
				hc.add(knowledgeBase.put(e));
			} catch (ReasoningException ex) {
				throw new RuntimeReasoningException(ex);
			}
		}
		return ((List<Handle<E>>) handleCollection).addAll(index, hc);
	}

	@Override
	public E get(int index) {
		return ((HandleImpl<E> )((List<Handle<E>>) handleCollection).get(index)).get();
	}

	@Override
	public int indexOf(Object o) {
		Handle<E> h = knowledgeBase.getHandle(o);
		return h==null ? -1 : ((List<Handle<E>>) handleCollection).indexOf(h);
	}

	@Override
	public int lastIndexOf(Object o) {
		Handle<E> h = knowledgeBase.getHandle(o);
		return h==null ? -1 : ((List<Handle<E>>) handleCollection).lastIndexOf(h);
	}

	private class HandleIterator implements ListIterator<E> {
		
		ListIterator<Handle<E>> master; 

		HandleIterator(ListIterator<Handle<E>> master) {
			this.master = master;
		}
		
		@Override
		public void add(E e) {
			try {
				master.add(knowledgeBase.put(e));
			} catch (ReasoningException ex) {
				throw new RuntimeReasoningException(ex);
			}
		}

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

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

		@Override
		public E next() {
			return ((HandleImpl<E>) master.next()).get();
		}

		@Override
		public int nextIndex() {
			return master.nextIndex();
		}

		@Override
		public E previous() {
			return ((HandleImpl<E>) master.previous()).get();
		}

		@Override
		public int previousIndex() {
			return master.previousIndex();
		}

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

		@Override
		public void set(E e) {
			try {
				master.set(knowledgeBase.put(e));
			} catch (ReasoningException ex) {
				throw new RuntimeReasoningException(ex);
			}			
		}
	};
	
	
	@Override
	public ListIterator<E> listIterator() {
		return new HandleIterator(((List<Handle<E>>) handleCollection).listIterator());
	}

	@Override
	public ListIterator<E> listIterator(int index) {
		return new HandleIterator(((List<Handle<E>>) handleCollection).listIterator(index));
	}

	@Override
	public E remove(int index) {
		try {
			return (E) knowledgeBase.get(((List<Handle<E>>) handleCollection).remove(index));
		} catch (ReasoningException e) {
			throw new RuntimeReasoningException(e);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public E set(int index, E element) {
		try {
			Handle h = ((List<Handle<E>>) handleCollection).set(index, knowledgeBase.put(element));
			return (E) knowledgeBase.get(h);
		} catch (ReasoningException e) {
			throw new RuntimeReasoningException(e);
		}
	}

	@Override
	public List<E> subList(int fromIndex, int toIndex) {
		return new HandleList<E>(knowledgeBase, ((List<Handle<E>>) handleCollection).subList(fromIndex, toIndex));
	}
	
	
}
