package com.github.davidmoten.rtree;

import java.util.Comparator;

import rx.Observable;
import rx.functions.Func1;

import com.github.davidmoten.util.ImmutableStack;
import com.google.common.base.Optional;
import com.google.common.collect.Lists;

public class RTree {

	private final Optional<Node> root;
	private final Context context;

	private RTree(Optional<Node> root, Context context) {
		this.root = root;
		this.context = context;
	}

	private RTree(Node root, Context context) {
		this(Optional.of(root), context);
	}

	public RTree() {
		this(Optional.<Node> absent(), Context.DEFAULT);
	}

	public RTree(int maxChildren) {
		this(Optional.<Node> absent(), new Context(maxChildren,
				new QuadraticSplitter()));
	}

	public RTree(int maxChildren, Splitter splitter) {
		this(Optional.<Node> absent(), new Context(maxChildren, splitter));
	}

	public static Builder builder() {
		return new Builder();
	}

	public static class Builder {

		private int maxChildren = 8;
		private Splitter splitter = new QuadraticSplitter();

		private Builder() {
		}

		public Builder maxChildren(int maxChildren) {
			this.maxChildren = maxChildren;
			return this;
		}

		public Builder splitter(Splitter splitter) {
			this.splitter = splitter;
			return this;
		}

		public RTree build() {
			return new RTree(maxChildren, splitter);
		}
	}

	public RTree add(Entry entry) {
		if (root.isPresent())
			return new RTree(root.get().add(entry,
					ImmutableStack.<NonLeaf> empty()), context);
		else
			return new RTree(new Leaf(Lists.newArrayList(entry), context),
					context);
	}

	public Observable<Entry> search(
			Func1<? super Rectangle, Boolean> criterion,
			Optional<Comparator<Rectangle>> comparator) {
		if (root.isPresent())
			return Observable.create(new OnSubscribeSearch(root.get(),
					criterion, comparator));
		else
			return Observable.empty();
	}

	public static final Comparator<Rectangle> ascendingDistance(
			final Rectangle r) {
		return new Comparator<Rectangle>() {
			@Override
			public int compare(Rectangle r1, Rectangle r2) {
				return ((Double) r.distance(r1)).compareTo(r.distance(r2));
			}
		};
	}

	public static Func1<Rectangle, Boolean> overlaps(final Rectangle r) {
		return new Func1<Rectangle, Boolean>() {
			@Override
			public Boolean call(Rectangle rectangle) {
				return r.overlaps(rectangle);
			}
		};
	}

	public Observable<Entry> nearest(Rectangle r) {
		return search(overlaps(r), Optional.of(ascendingDistance(r)));
	}

	public Observable<Entry> search(Func1<? super Rectangle, Boolean> criterion) {
		return search(criterion, Optional.<Comparator<Rectangle>> absent());
	}

	public Observable<Entry> search(final Rectangle r) {
		return search(overlaps(r));
	}

	public Observable<Entry> search(final Rectangle r, final double maxDistance) {
		return search(new Func1<Rectangle, Boolean>() {
			@Override
			public Boolean call(Rectangle rectangle) {
				return r.distance(rectangle) <= maxDistance;
			}
		});
	}

	public Observable<Entry> entries() {
		return search(new Func1<Rectangle, Boolean>() {
			@Override
			public Boolean call(Rectangle rectangle) {
				return true;
			}
		});
	}

	public Visualizer visualize(int width, int height, Rectangle view,
			int maxDepth) {
		return new Visualizer(this, width, height, view);
	}

	Optional<Node> root() {
		return root;
	}

}

@@ -31,16 +31,67 @@
 rtree;%0A%0A
+import static com.google.common.base.Optional.of;%0A%0A
 import j
@@ -541,25 +541,16 @@
 %0A%09%09this(
-Optional.
 of(root)
@@ -1655,26 +1655,14 @@
 rch(
-%0A%09%09%09
 Func1%3C
-? super 
 Rect
@@ -2154,32 +2154,301 @@
 ;%0A%09%09%09%7D%0A%09%09%7D;%0A%09%7D%0A%0A
+%09public static final Comparator%3CRectangle%3E descendingDistance(%0A%09%09%09final Rectangle r) %7B%0A%09%09return new Comparator%3CRectangle%3E() %7B%0A%09%09%09@Override%0A%09%09%09public int compare(Rectangle r1, Rectangle r2) %7B%0A%09%09%09%09return ((Double) r.distance(r2)).compareTo(r.distance(r1));%0A%09%09%09%7D%0A%09%09%7D;%0A%09%7D%0A%0A
 %09public static F
@@ -2734,21 +2734,123 @@
 r), 
-Optional.of(a
+of(ascendingDistance(r)));%0A%09%7D%0A%0A%09public Observable%3CEntry%3E furthest(Rectangle r) %7B%0A%09%09return search(overlaps(r), of(de
 scen
@@ -2915,16 +2915,8 @@
 nc1%3C
-? super 
 Rect

simplify signature