/* unfolditerator.vala
 *
 * Copyright (C) 2011  Maciej Piechotka
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.

 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *
 * Author:
 * 	Maciej Piechotka <uzytkownik2@gmail.com>
 */

internal class Gee.UnfoldIterator<G> : Object, Traversable<G>, Iterator<G> {
	public UnfoldIterator (owned UnfoldFunc<G> func, owned Lazy<G>? current = null) {
		_current = (owned)current;
		_func = (owned)func;
		_end = false;
	}

	public bool next () {
		if (has_next ()) {
			if (_current != null)
				_current.eval ();
			_current = (owned)_next;
			return true;
		}
		return false;
	}

	public bool has_next () {
		if (_end)
			return false;
		if (_next != null)
			return true;
		_next = _func ();
		if (_next == null)
			_end = true;
		return _next != null;
	}

	public new G get () {
		assert (_current != null);
		return _current.value;
	}

	public void remove () {
		assert_not_reached ();
	}

	public bool valid { get { return _current != null; } }
	public bool read_only { get { return true; } }

	public bool foreach (ForallFunc<G> f) {
		if (_current != null) {
			if (!f (_current.value)) {
				return false;
			}
		}
		if (_next != null) {
			_current = (owned)_next;
			if (!f (_current.value)) {
				return false;
			}
		} else if (_end) {
			return true;
		}
		if (_current == null) {
			_current = _func ();
			if (_current == null) {
				_end = true;
				return true;
			} else {
				if (!f (_current.value)) {
					return false;
				}
			}
		}
		while ((_next = _func ()) != null) {
			_current = (owned)_next;
			if (!f (_current.value)) {
				return false;
			}
		}
		_end = true;
		return true;
	}

	private UnfoldFunc<G> _func;
	private Lazy<G>? _current;
	private Lazy<G>? _next;
	private bool _end;
}
