package migl.util;

import java.util.Iterator;
import java.util.function.Function;

public class ConsListImpl<E> extends Cons<E, ConsList<E>> implements ConsList<E>{
	
	private final int size;

	public ConsListImpl(E left, ConsList<E> right) {
		super(left, right);
		if(right == null) {
			throw new IllegalArgumentException();
		}
		this.size = 1 + right.size();
	}

	@Override
	public Iterator<E> iterator() {
		return new Iterator<E>() {
			private ConsList<E> current = ConsListImpl.this;
			@Override
			public boolean hasNext() {
				return !current.isEmpty();
			}
			
			@Override
			public E next() {
				E e = current.car();
				current = current.cdr();
				return e;
			}
		};
	}

	@Override
	public ConsList<E> prepend(E e) {
		return new ConsListImpl<>(e, this);
	}

	@Override
	public ConsList<E> append(E e) {
		return appendRec(e, this);
	}
	
	private ConsList<E> appendRec(E e, ConsList<E> list) {
		if(list.isEmpty()) {
			return new ConsListImpl<>(e, list);
		}
		return new ConsListImpl<>(list.car(), this.appendRec(e, list.cdr()));
	}

	@Override
	public boolean isEmpty() {
		//Jamais vide sinon on utilise ConsEmptyList
		return false;
	}

	@Override
	public E car() {
		return this.left();
	}

	@Override
	public ConsList<E> cdr() {
		return this.right();
	}

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

	@Override
	public <T> ConsList<T> map(Function<E, T> f) {
		ConsList<T> result = new ConsEmptyList<>();
		for(E e : this) {
			result = result.append(f.apply(e));
		}
		return result;
	}
	
	@Override
	public String toString() {
		StringBuilder str = new StringBuilder("(");
		for(E e : this) {
			if(e == null) {
				str.append("null ");
			} else {
				str.append(e + " ");
			}
		}
		return str.toString().trim() + ")";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
        int result = super.hashCode();
        return prime * result + this.size;
	}

	@Override
	public boolean equals(Object obj) {
		//Equals de cons suffisant
		return super.equals(obj);
	}
	
}
