/*
 * Java Genetic Algorithm Library (@__identifier__@).
 * Copyright (c) @__year__@ Franz Wilhelmstötter
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Author:
 *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at)
 */
package org.jenetics.engine;

import static java.util.Objects.requireNonNull;

import java.util.Spliterator;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

import org.jenetics.Gene;

/**
 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
 * @since 3.0
 * @version 3.0
 */
final class EvolutionSpliterator<
	G extends Gene<?, G>,
	C extends Comparable<? super C>
>
	implements Spliterator<EvolutionResult<G, C>>
{

	private final Supplier<EvolutionStart<G, C>> _initial;
	private final Function<? super EvolutionStart<G, C>, EvolutionResult<G, C>> _evolution;
	private final Predicate<? super EvolutionResult<G, C>> _proceed;
	private final int _level;
	private long _estimate;

	private final AtomicReference<EvolutionStart<G, C>> _next = new AtomicReference<>();

	EvolutionSpliterator(
		final Supplier<EvolutionStart<G, C>> initial,
		final Function<? super EvolutionStart<G, C>, EvolutionResult<G, C>> evolution,
		final Predicate<? super EvolutionResult<G, C>> proceed,
		final int level,
		final long estimate
	) {
		_evolution = requireNonNull(evolution);
		_initial = requireNonNull(initial);
		_proceed = requireNonNull(proceed);
		_level = level;
		_estimate = estimate;
	}

	EvolutionSpliterator(
		final Supplier<EvolutionStart<G, C>> initial,
		final Function<? super EvolutionStart<G, C>, EvolutionResult<G, C>> evolution,
		final Predicate<? super EvolutionResult<G, C>> proceed
	) {
		this(initial, evolution, proceed, 0, Long.MAX_VALUE);
	}

	int _count = 0;

	@Override
	public boolean
	tryAdvance(final Consumer<? super EvolutionResult<G, C>> action) {
		if (_next.get() == null) {
			_next.set(_initial.get());
		}
		System.out.println("tryAdvance: " + _level + ":" + ++_count);

		final EvolutionResult<G, C> result = _evolution.apply(_next.get());
		action.accept(result);
		_next.set(result.next());

		return _proceed.test(result);
	}

	@Override
	public Spliterator<EvolutionResult<G, C>> trySplit() {
		System.out.println("trySplit: " + _level);

		return _estimate > 0
			? new EvolutionSpliterator<>(
				this::next, _evolution, _proceed, _level + 1, _estimate >>>= 1)
			: null;
	}

	private EvolutionStart<G, C> next() {
		final EvolutionStart<G, C> next = _next.get();
		return next != null ? next : _initial.get();
	}

	@Override
	public long estimateSize() {
		return _estimate;
	}

	@Override
	public int characteristics() {
		return NONNULL | IMMUTABLE;
	}

}

@@ -847,60 +847,8 @@
 or;%0A
-import java.util.concurrent.atomic.AtomicReference;%0A
 impo
@@ -1128,19 +1128,29 @@
 version 
-3.0
+!__version__!
 %0A */%0Afin
@@ -1503,34 +1503,8 @@
 ed;%0A
-%09private final int _level;
 %0A%09pr
@@ -1525,17 +1525,16 @@
 timate;%0A
-%0A
 %09private
@@ -1538,30 +1538,8 @@
 ate 
-final AtomicReference%3C
 Evol
@@ -1554,17 +1554,16 @@
 rt%3CG, C%3E
-%3E
  _next =
@@ -1568,34 +1568,23 @@
  = n
-ew AtomicReference%3C%3E();%0A%0A%09
+ull;%0A%0A%09private 
 Evol
@@ -1792,27 +1792,8 @@
 ed,%0A
-%09%09final int level,%0A
 %09%09fi
@@ -1937,26 +1937,8 @@
 d);%0A
-%09%09_level = level;%0A
 %09%09_e
@@ -2214,11 +2214,8 @@
 eed,
- 0,
  Lon
@@ -2236,26 +2236,8 @@
 %09%7D%0A%0A
-%09int _count = 0;%0A%0A
 %09@Ov
@@ -2338,22 +2338,16 @@
 f (_next
-.get()
  == null
@@ -2358,21 +2358,19 @@
 %09%09%09_next
-.set(
+ = 
 _initial
@@ -2379,78 +2379,13 @@
 et()
-)
 ;%0A%09%09%7D
-%0A%09%09System.out.println(%22tryAdvance: %22 + _level + %22:%22 + ++_count);
 %0A%0A%09%09
@@ -2443,22 +2443,16 @@
 ly(_next
-.get()
 );%0A%09%09act
@@ -2482,13 +2482,11 @@
 next
-.set(
+ = 
 resu
@@ -2494,17 +2494,16 @@
 t.next()
-)
 ;%0A%0A%09%09ret
@@ -2604,54 +2604,8 @@
 ) %7B%0A
-%09%09System.out.println(%22trySplit: %22 + _level);%0A%0A
 %09%09re
@@ -2664,18 +2664,16 @@
 %09%09%09%09
-this::next
+_initial
 , _e
@@ -2695,20 +2695,8 @@
 eed,
- _level + 1,
  _es
@@ -2729,147 +2729,8 @@
 %09%7D%0A%0A
-%09private EvolutionStart%3CG, C%3E next() %7B%0A%09%09final EvolutionStart%3CG, C%3E next = _next.get();%0A%09%09return next != null ? next : _initial.get();%0A%09%7D%0A%0A
 %09@Ov

Implement 'trySplit' for 'EvolutionSpliterator'.