#include <assert.h>

#define rtr_box_touch_(db, query) \
	(!(db->x1 > query->x2) && !(db->x2 < query->x1) && !(db->y1 > query->y2) && !(db->y2 < query->y1))

#define rtr_box_touch(db, query) rtr_box_touch_((db), (query))

/* go one level up: set it->curr:it->n to the next sibling of the parent
   of curren it->curr */
static void RTR(pop2)(RTR(it2_t) *it)
{
	const RTR(t) *from;

	retry:;
	from = it->curr;

	it->curr = it->curr->parent;
	if (it->curr != NULL) {
		int n, idx = -1;
		for(n = 0; n < it->curr->used; n++) {
			if (it->curr->child.node[n] == from) {
				idx = n;
				break;
			}
		}
		assert(idx >= 0);
		idx++;
		if (idx >= it->curr->used)
			goto retry;
		it->n = idx;
	}
}

void *RTR(next2)(RTR(it2_t) *it)
{
	retry:;

	if (it->curr == 0)
		return NULL;

	if (it->curr->is_leaf) {
		while(it->n < it->curr->used) {
			if (rtr_box_touch(it->curr->child.obj[it->n].box, &it->query)) {
				it->n++;
				it->cnt++;
				return it->curr->child.obj[it->n-1].obj;
			}
			it->n++;
		}
		/* ran out of leaf objects, pop */
		RTR(pop2)(it);
		goto retry;
	}
	else {
		/* tree node */
		while(it->n < it->curr->used) {
			if (rtr_box_touch(&it->curr->child.node[it->n]->bbox, &it->query)) {
				/* found a new node we shall descend into - push */
				it->curr = it->curr->child.node[it->n];
				it->n = 0;
				goto retry;
			}
			it->n++;
		}
		/* ran out of non-leaf objects, pop */
		RTR(pop2)(it);
		goto retry;
	}
}


void *RTR(first2)(RTR(it2_t) *it, const RTR(t) *root, const RTR(box_t) *query)
{
	it->cnt = 0;
	it->curr = root;
	it->n = 0;
	it->query = *query;
	return RTR(next2)(it);
}


void *RTR(all_next2)(RTR(it2_t) *it)
{
	retry:;

	if (it->curr == 0)
		return NULL;

	if (it->curr->is_leaf) {
		while(it->n < it->curr->used) {
			it->n++;
			it->cnt++;
			return it->curr->child.obj[it->n-1].obj;
		}
		/* ran out of leaf objects, pop */
		RTR(pop2)(it);
		goto retry;
	}
	else {
		/* tree node */
		while(it->n < it->curr->used) {
			/* found a new node we shall descend into - push */
			it->curr = it->curr->child.node[it->n];
			it->n = 0;
			goto retry;
		}
		/* ran out of non-leaf objects, pop */
		RTR(pop2)(it);
		goto retry;
	}
}

void *RTR(all_first2)(RTR(it2_t) *it, const RTR(t) *root)
{
	it->cnt = 0;
	it->curr = root;
	it->n = 0;
	return RTR(all_next2)(it);
}

#undef rtr_box_touch_
#undef rtr_box_touch
