#include "BarnesHutTree.hpp"
#include "TreeNode.hpp"

namespace nbody {
	BarnesHutTree::BarnesHutTree() {
	}

	BarnesHutTree::~BarnesHutTree() {
	}

	vector<Box> BarnesHutTree::splitBB(TreeNode* node) {
		vector<Box> result;

		for (int i = 0; i < 8; i++) {
			Box current = node->getBB();

			for (int j = 0; j < 3; j++) {
				double middle = node->getBB().getMin(j) + (node->getBB().getMax(j) - node->getBB().getMin(j)) / 2.0;

				if (i & (1 >> j)) {
					current.setMin(j, middle);
				} else {
					current.setMax(j, middle);
				}
			}
			result.push_back(current);
		}
		return result;
	}

	void BarnesHutTree::build(vector<Body> bodies) {
		TreeNode* current;

		this->clean();
		if (bodies.empty()) return;
		this->nodes->insertAfter(new TreeNode());
		current = this->nodes->next;
		current->bodies = bodies;
		current->extendBBforBodies();
		current->extendBBtoCube();
		while (current != this->nodes) {
			if (current->isSplitable()) {
				vector<Box> subboxes = this->splitBB(current);
				vector<Body> localBodies = current->getBodies();
				TreeNode* after = current->next;

				for (vector<Box>::iterator bit = subboxes.begin(); bit != subboxes.end(); bit++) {
					TreeNode* child = new TreeNode();

					child->bb = *bit;
					child->bodies = bit->containedBodies(localBodies);
					current->next->insertBefore(child);
				}
				for (TreeNode* child = current->next; child != after->prev; child = child->next) {
					child->afterSubtree = child->next;
				}
				after->prev->afterSubtree = after->afterSubtree;
				current->bodies.clear();
			}

			current = current->next;
		}

		/*
		this->nodes->insertAfter(new TreeNode());
		current = this->nodes->next;
		current->bodies = bodies;
		current->extendBBforBodies();
		current->extendBBtoCube();
		while (current != this->nodes) {
			current++;
		}
		*/
		/*
		while (current != this->nodes) {
			if (current->isSplitable()) {
				vector<Box> subboxes = this->splitBB(current);
				vector<Body> localBodies = current->getBodies();

				for (vector<Box>::iterator bit = subboxes.begin(); bit != subboxes.end(); bit++) {

				}
			}
			current++; //TODO: check if needed
		}
		*/
		/*
		this->nodes = new TreeNode(this);
		this->nodes->bodies = bodies;
		this->nodes->extendBBforBodies();
		this->nodes->extendBBtoCube();
		current = this->nodes;
		do {

		} while (current != this->nodes);

		it = this->nodes.begin();
		while (it != this->nodes.end()) {
			(*it)->afterSubtree = it;
			(*it)->afterSubtree++;
			if ((*it)->isSplitable()) {
				vector<Box> subboxes = this->splitBB(*it);
				vector<Body> localBodies = (*it)->getBodies();

				for (vector<Box>::iterator bit = subboxes.begin(); bit != subboxes.end(); bit++) {
					TreeNode* current = new TreeNode(this);

					current->bb = *bit;
					current->bodies = bit->containedBodies(localBodies);
					//this->nodes.insert((*it)->afterSubtree, current);
				}
				(*it)->bodies.clear();
			}
			it++;
		}
		*/
	}

}
