#include "BarnesHutTree.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) {
		vector<TreeNode*>::iterator it;

		this->clean();
		this->nodes.push_back(new TreeNode());
		std::copy(bodies.begin(), bodies.end(), this->nodes.front()->bodies.begin());
		this->nodes.front()->extendBBforBodies();
		this->nodes.front()->extendBBtoCube();
		it = this->nodes.begin();
		while (it != this->nodes.end()) {
			(*it)->afterSubtree = it;
			(*it)->afterSubtree++;
			if ((*it)->isSplitable()) {
				vector<Box> subboxes = this->splitBB(*it);
				for (vector<Box>::iterator bit = subboxes.begin(); bit != subboxes.end(); bit++) {
					TreeNode* current = new TreeNode();

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

}
