#ifndef OctreeSupport_H
#define OctreeSupport_H

#include <ostream>


/*
These structs are designed to be used by/with Octree and OctreeNode classes.
For documentation, go look at the top of Octree.hpp
*/

struct Path {
	unsigned int x, y, z;
	Path(unsigned int X, unsigned int Y, unsigned int Z): x(X), y(Y), z(Z) {}
	Path(void): x(0), y(0), z(0) {}
	
	void Print(void) const;
};

/****************************************************************************/

struct Vector {
	double x, y, z;
	Vector(const Vector& V): x(V.x), y(V.y), z(V.z) {}
	Vector(const double X, const double Y, const double Z): x(X), y(Y), z(Z) {}
	Vector(void): x(0), y(0), z(0) {}
	void SetValues(const double X, const double Y, const double Z) {
		x = X;
		y = Y;
		z = Z;
	}
	Vector& operator*=(const double scaleFactor);
	Vector& operator/=(const double scaleFactor);
	
	double Norm() const;
	
	Vector& operator-=(const Vector& V);
	Vector& operator+=(const Vector& V);
	
	bool operator==(const Vector& V) const {return ((V.x == x) && (V.y == y) && (V.z == z));}
	double Dot(const Vector& V) const { return V.x * x + V.y * y + V.z * z;}
	
	bool StrictlyLessThan(const Vector& V)const {
		return ((x < V.x) && (y < V.y) && (z < V.z));
	}
	bool StrictlyGreaterThan(const Vector& V)const {
		return ((x > V.x) && (y > V.y) && (z > V.z));
	}
	bool StrictlyLessOrEqualTo(const Vector& V)const {
		return ((x <= V.x) && (y <= V.y) && (z <= V.z));
	}
	bool StrictlyGreaterOrEqualTo(const Vector& V)const {
		return ((x >= V.x) && (y >= V.y) && (z >= V.z));
	}
	
	void Print(void) const;
};

Vector operator+ (Vector U, const Vector& V);
Vector operator- (Vector U, const Vector& V);

/****************************************************************************/
//for Octree.tcc
int Octree_PickMaxRatio(double& Xratio, const double Yratio, const double Zratio);
int Octree_PickMinPositiveRatio(const double Xratio, const double Yratio, const double Zratio);
//for OctreeNode.tcc
void OctreeNode_PrintTabs(int num);


/****************************************************************************/
/* PlanarFitNode holds a unit normal vector, and an offset.  These represent 
the plane (U' * X - offset == 0) with the <= side coounting as full, and 
the > side being empty.  'Full' and 'Empty' PlanarFitNodes have <0,0,0> as 
the unit normal so that nomatter where they are queried about, they always 
return (offset <= 0) which is the same as sign(offset).  In the OctreeNode use, 
PlanarFitNodes have an offset which is referenced to the lower-most corner of 
the node.  The Constructor which takes a set of points is designed to work with 
OctreeNode; indicies are passed in so that the array of points is not copied 
and subdividied by OctreeNode.  
*/
struct PlanarFitNode{
	Vector unitNormal;
	double offset;
	
	PlanarFitNode(): unitNormal(), offset(-1.0) {}
	PlanarFitNode(const Vector& inputVector, double inputOffset): unitNormal(inputVector), offset(inputOffset) {
		unitNormal/=unitNormal.Norm();
		
	}
	PlanarFitNode(const PlanarFitNode& toCopy): unitNormal(toCopy.unitNormal), offset(toCopy.offset) {}
	PlanarFitNode(const Vector * const points, const unsigned long * const indicies, int numPoints, const Vector& nodeLowerBounds, const Vector& outwardVector);
	
	PlanarFitNode(bool full): unitNormal(0.0,0.0,0.0) {
		if(full){
			offset = 1.0;
		}else{
			offset = -1.0;
		}
	}
	
	bool IsInside(Vector testPoint) const {return (testPoint.Dot(unitNormal) - offset) <= 0;}
	bool IsEmpty() const {return ((unitNormal.x == 0.0) && (unitNormal.y == 0.0) && (unitNormal.z == 0.0) && (offset == -1.0));}
	bool IsFull() const {return ((unitNormal.x == 0.0) && (unitNormal.y == 0.0) && (unitNormal.z == 0.0) && (offset == 1.0));}
	
	bool operator==(const PlanarFitNode& toCompare) const {return ((unitNormal == toCompare.unitNormal) && (offset == toCompare.offset));}
	
	operator double() const { 
		if(this->IsEmpty()){
			return 0.0;
		}else{
			return 1.0;
		}
	}
};
/****************************************************************************/

//ostream& operator<< (ostream& out, const PlanarFitNode& value);



#endif
