/**
 * 
 */
package eu.dnetlib.miscutils.collections;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import com.google.common.collect.Lists;

import eu.dnetlib.miscutils.functional.UnaryFunction;

/**
 * @author marko
 * 
 */
public class MappedCollection<T, K> implements Iterable<T> {
	private transient final Iterable<K> coll;
	private transient final UnaryFunction<T, K> mapper;

	/**
	 * Static helper function, makes usage shorter.
	 * 
	 * @param <X>
	 * @param coll
	 * @param filter
	 * @return
	 */
	public static <X, Y> Iterable<X> map(final Iterable<Y> coll, final UnaryFunction<X, Y> mapper) {
		return new MappedCollection<X, Y>(coll, mapper);
	}

	public static <X, Y> Iterable<X> map(final Y[] coll, final UnaryFunction<X, Y> mapper) {
		return new MappedCollection<X, Y>(coll, mapper);
	}

	/**
	 * Static helper function, makes common usage shorter.
	 * 
	 * @param <X>
	 * @param <Y>
	 * @param coll
	 * @param mapper
	 * @return
	 */
	public static <X, Y> List<X> listMap(final Iterable<Y> coll, final UnaryFunction<X, Y> mapper) {
		return Lists.newArrayList(map(coll, mapper));
	}

	public static <X, Y> List<X> listMap(final Y[] coll, final UnaryFunction<X, Y> mapper) {
		return Lists.newArrayList(map(coll, mapper));
	}

	/**
	 * Compatibility with pre 0.0.3 cnr-misc-utils.
	 * 
	 * @param coll
	 * @param mapper
	 */
	public MappedCollection(final Collection<K> coll, final UnaryFunction<T, K> mapper) {
		this.coll = coll;
		this.mapper = mapper;
	}

	public MappedCollection(final Iterable<K> coll, final UnaryFunction<T, K> mapper) {
		this.coll = coll;
		this.mapper = mapper;
	}

	public MappedCollection(final K[] coll, final UnaryFunction<T, K> mapper) {
		this.coll = Lists.newArrayList(coll);
		this.mapper = mapper;
	}

	class MappedIterator implements Iterator<T> {
		private transient final Iterator<K> iter;

		public MappedIterator() {
			this.iter = coll.iterator();
		}

		@Override
		public T next() {
			return mapper.evaluate(iter.next());
		}

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

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

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Iterable#iterator()
	 */
	@Override
	public Iterator<T> iterator() {
		return new MappedIterator();
	}

}
