public class Gth.GenericList<T> {
	public ListStore model;

	public GenericList () {
		model = new ListStore (typeof (T));
	}

	public ListStoreIterator<T> iterator () {
		return new ListStoreIterator<T> (model);
	}

	public T? first () {
		return model.get_item (0);
	}

	public T? get (int pos) {
		return ((pos >= 0) && (pos < length ())) ? model.get_item (pos) : null;
	}

	public inline bool is_empty () {
		return model.n_items == 0;
	}

	public inline uint length () {
		return model.n_items;
	}

	public int find (T _item) {
		var iter = new ListIterator<T> (model);
		return iter.find_item (_item);
	}

	public void copy (GenericList<T> other) {
		model.remove_all ();
		foreach (unowned var item in other) {
			model.append ((Object) item);
		}
	}

	public GenericList<T> duplicate () {
		var other = new GenericList<T>();
		other.copy (this);
		return other;
	}

	public bool remove (T item) {
		var pos = find (item);
		if (pos < 0) {
			return false;
		}
		model.remove ((uint) pos);
		return true;
	}

	public void sort (CompareDataFunc<T> func) {
		model.sort (func);
	}

	public void reverse_order () {
		var len = (int) model.n_items;
		for (int i = len - 2; i >= 0; i--) {
			var obj = model.get_object ((uint) i);
			model.remove ((uint) i);
			model.append (obj);
		}
	}

	public List<T> to_glist () {
		List<T> list = new List<T> ();
		foreach (unowned T item in this) {
			list.append (item);
		}
		return list;
	}
}

public class Gth.IterableList<T> {
	public ListModel model;

	public IterableList (ListModel _model) {
		model = _model;
	}

	public ListIterator<T> iterator () {
		return new ListIterator<T> (model);
	}
}

public class Gth.ListIterator<T> {
	public ListIterator (ListModel _model) {
		model = _model;
		idx = -1;
		item = null;
		started = false;
		deleted = false;
	}

	public unowned T get () {
		return item;
	}

	public bool previous () {
		if (started && (item == null)) {
			return false;
		}
		if (!started) {
			idx = (int) model.get_n_items () - 1;
			started = true;
		}
		else {
			idx = idx - 1;
		}
		item = model.get_item (idx);
		deleted = false;
		return item != null;
	}

	public bool next () {
		if (started && (item == null)) {
			return false;
		}
		if (!started) {
			idx = 0;
			started = true;
		}
		else if (!deleted) {
			idx = idx + 1;
		}
		item = model.get_item (idx);
		deleted = false;
		return item != null;
	}

	public bool has_next () {
		return model.get_item ((!started ? 0 : deleted ? idx : idx + 1)) != null;
	}

	public bool has_previous () {
		return model.get_item ((!started ? (int) model.get_n_items () - 1 : idx - 1)) != null;
	}

	public int index () {
		return idx;
	}

	public int find_item (T _item) {
		while (next ()) {
			if (item == _item) {
				return index ();
			}
		}
		return -1;
	}

	public T? find_first_item (MatchGenericItemFunc<T> match_func) {
		while (next ()) {
			if (match_func (item)) {
				return item;
			}
		}
		return null;
	}

	public int find_first (MatchGenericItemFunc<T> match_func) {
		while (next ()) {
			if (match_func (item)) {
				return index ();
			}
		}
		return -1;
	}

	public GenericList<T> filter (MatchGenericItemFunc<T> match_func) {
		var result = new GenericList<T>();
		while (next ()) {
			if (match_func (item)) {
				result.model.append (item as Object);
			}
		}
		return result;
	}

	ListModel model;
	T item;
	protected int idx;
	protected bool started;
	protected bool deleted;
}

public class Gth.ListStoreIterator<T> : Gth.ListIterator<T> {
	public ListStoreIterator (ListStore _model) {
		base (_model);
		store = _model;
	}

	public void remove () {
		if (!started) {
			return;
		}
		store.remove ((uint) idx);
		deleted = true;
	}

	ListStore store;
}

public delegate bool MatchGenericItemFunc<T> (T item);
