package org.simpleflatmapper.map.mapper;

import org.simpleflatmapper.map.MappingContext;
import org.simpleflatmapper.map.MappingException;
import org.simpleflatmapper.map.SetRowMapper;
import org.simpleflatmapper.util.CheckedConsumer;
import org.simpleflatmapper.util.Function;

import java.util.Iterator;
//IFJAVA8_START
import java.util.stream.Stream;
//IFJAVA8_END

public final class TransformSetRowMapper<ROW, SET, I, O, E extends Exception> implements SetRowMapper<ROW, SET, O, E> {

	private final SetRowMapper<ROW, SET, I, E> delegate;
	private final Function<? super I, ? extends O> transformer;

	public TransformSetRowMapper(SetRowMapper<ROW, SET, I, E> delegate, Function<I, O> transformer) {
		this.delegate = delegate;
		this.transformer = transformer;
	}

	@Override
	public <H extends CheckedConsumer<? super O>> H forEach(SET source, final H handler) throws E, MappingException {
		delegate.forEach(source, new TransformCheckedConsumer<I, O>(handler, transformer));
		return handler;
	}

	@Override
	public Iterator<O> iterator(SET source) throws E, MappingException {
		return new TransformIterator<I, O>(delegate.iterator(source), transformer);
	}

	//IFJAVA8_START
	@Override
	public Stream<O> stream(SET source) throws E, MappingException {
		return delegate.stream(source).map(transformer::apply);
	}
	//IFJAVA8_END

	@Override
	public O map(ROW source) throws MappingException {
		return transformer.apply(delegate.map(source));
	}

	@Override
	public O map(ROW source, MappingContext<? super ROW> context) throws MappingException {
		return transformer.apply(delegate.map(source, context));
	}

	private static class TransformIterator<I, O> implements Iterator<O> {
		private final Iterator<I> it;
		private final Function<? super I, ? extends O> transformer;

		public TransformIterator(Iterator<I> it, Function<? super I, ? extends O> transformer) {
			this.it = it;
			this.transformer = transformer;
		}

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

		@Override
		public O next() {
			return transformer.apply(it.next());
		}
	}

	private static class TransformCheckedConsumer<I, O> implements CheckedConsumer<I> {
		private final CheckedConsumer<? super O> handler;
		private final Function<? super I, ? extends O> transformer;

		public TransformCheckedConsumer(CheckedConsumer<? super O> handler, Function<? super I, ? extends O> transformer) {
			this.handler = handler;
			this.transformer = transformer;
		}

		@Override
		public void accept(I i) throws Exception {
			handler.accept(transformer.apply(i));
		}
	}
}

@@ -1919,32 +1919,130 @@
 ansformer;%0A%09%09%7D%0A%0A
+%09%09@Override%0A%09%09public void remove() %7B%0A%09%09%09throw new UnsupportedOperationException(%22remove%22);%0A%09%09%7D%0A%09%09%0A
 %09%09@Override%0A%09%09pu

add remove