#include <cfloat>
#include <cstdlib>
#include <iostream>
#include "TreeNode.hpp"

namespace nbody {
	using namespace std;


	TreeNode::TreeNode(Tree* tree) {
		for (int i = 0; i < 3; i++) {
			this->bb.min[i] = 1.0;
			this->bb.max[i] = -1.0;
		}
		this->afterSubtree = NULL;
		this->prev = this;
		this->next = this;
		this->leaf = true;
		this->tree = tree;
	}

	TreeNode::~TreeNode() {
	}

	Box TreeNode::getBB() {
		return this->bb;
	}

	bool TreeNode::isSplitable() {
		if (this->bodies.size() < 2) {
			return false;
		}
		if (this->bb.volume() <= FLT_EPSILON) {
			return false;
		}
		return true;
	}

	void TreeNode::extendBBforBodies() {
		if (this->bodies.empty()) return;
		for (int i = 0; i < 3; i++) {
			this->bb.min[i] = this->bodies.front().getPosition(i);
			this->bb.max[i] = this->bodies.front().getPosition(i);
		}
		for (vector<Body>::iterator it = this->bodies.begin(); it != this->bodies.end(); it++) {
			for (int i = 0; i < 3; i++) {
				if (it->getPosition(i) < this->bb.min[i]) {
					this->bb.min[i] = it->getPosition(i);
				}
				if (it->getPosition(i) > this->bb.max[i]) {
					this->bb.max[i] = it->getPosition(i);
				}
			}
		}
	}

	void TreeNode::extendBBtoCube() {
		this->bb.extendToCube();
	}

	vector<Body> TreeNode::getBodies() {
		return this->bodies;
	}

	void TreeNode::insertBefore(TreeNode* node) {
		node->next = this;
		node->prev = this->prev;
		this->prev->next = node;
		this->prev = node;
	}

	void TreeNode::insertAfter(TreeNode* node) {
		this->next->insertBefore(node);
	}

	void TreeNode::unlink() {
		this->next->prev = this->prev;
		this->prev->next = this->next;
		this->next = this;
		this->prev = this;
	}

	bool TreeNode::isCorrect() {
		if (this->afterSubtree == NULL) {
			cout << "after subtree null" << endl;
			return false;
		}
		if (!this->bb.isCorrect()) {
			cout << "bb wrong" << endl;
			return false;
		}
		for (int i = 0; i < 3; i++) {
			if (this->bb.min[i] > this->bb.max[i]) {
				cout << "bb " << i << " min " << this->bb.min[i] << " " << this->bb.max[i] << endl;
				return false;
			}
		}
		for (vector<Body>::iterator it = this->bodies.begin(); it != this->bodies.end(); it++) {
			if (!this->bb.isContained(*it)) {
				cout << "bb out of bounds" << endl;
				return false;
			}
		}
		if (!this->leaf) {
			TreeNode* current = this->next;
			int children = 0;

			while (current != NULL && current != this->afterSubtree) {
				current = current->afterSubtree;
				children++;
			}
			if (current == NULL) {
				cout << "afterSubtree null" << endl;
				return false;
			}
			if (children != this->tree->numberOfChildren()) {
				cout << "wrong number of children " << children << endl;
				return false;
			}
			current = this->next;
			for (int i = 0; i < this->tree->numberOfChildren(); i++) {
				current = current->afterSubtree;
			}
			if (current != this->afterSubtree) {
				cout << "last sibling afterSubtree inconsistent" << endl;
				return false;
			}
		}
		if (!this->leaf && this->bodies.size() > 0) {
			cout << "non-empty inner node" << endl;
			return false;
		}
		return true;
	}

	void TreeNode::update() {
		if (this->leaf) {

		}
	}

	void TreeNode::print() {
		this->bb.print();
		for (vector<Body>::iterator it = this->bodies.begin(); it != this->bodies.end(); it++) {
			cout << "  ";
			it->print();
		}
	}
}
