
#ifndef _JL_OctTree_H_
#define _JL_OctTree_H_

#include <stdlib.h>
#include <iostream.h>

#include "raycastnode.h"
#include "raycastablelist.h"

class Ray;
class _OctTreeNode;

class OctTree : public RayCastNode {

	private:
		_OctTreeNode	*_root;
		int				_child_limit;
		int				_depth_limit;

	public:
		static int		_intersect_count;

	public:
		OctTree();
		OctTree(RayCastNode *p, float, float, float, float, float, float);
		OctTree(RayCastNode *p, const Bounds3d &B);
		OctTree(const OctTree &G) { CopyFrom(G); }
		virtual ~OctTree();

		virtual RayCastable* CopyRayCastable() const
				{ return new OctTree(*this); }

		OctTree& CopyFrom(const OctTree&);
		OctTree& operator=(const OctTree &G) { return CopyFrom(G); }

		friend ostream& operator<<(ostream&, const OctTree&);
//		friend istream& operator>>(istream&, OctTree&);

		virtual void PlaceRayCastable(RayCastable *object);

		virtual Prim* Intersect(const Ray &ray, RCFloat &hit);

		virtual int IntersectLinespace(const Ray&, const Ray&,
									   const Ray&, const Ray&,
									   const Vec4&, const Vec4&,
									   const Vec4&, const Vec4&) {

				cerr << "OctTree::IntersectLinespace() not implemented"
					 << endl;
				exit(-1);
				return 0;
			}

	
		int CountChildren();
		int CountLeaves();
		int MaxDepth();
};


class _OctTreeNode;
typedef _OctTreeNode *_OctTreeNodePtr;
class _OctTreeNode {

	friend class OctTree;

	private:
		_OctTreeNodePtr		_children[8];
		RayCastNodePtr		_at_this_level;
		Bounds3d			_bounds3d;
		float				_mid_x, _mid_y, _mid_z;

	private:
		_OctTreeNode();
		_OctTreeNode(Bounds3d &B);
		_OctTreeNode(const _OctTreeNode &O) { CopyFrom(O); }
		~_OctTreeNode();

		_OctTreeNode& CopyFrom(const _OctTreeNode&);

		void Insert(RayCastable *object, RayCastNode *p,
					int child_limit, int depth_limit);

		void InsertToChild(RayCastable *object, RayCastNode *p,
						   int child_limit, int depth_limit,
						   int child_x, int child_y, int child_z);

		Prim* Intersect(const Ray &ray, RCFloat &hit);

		int CountChildren();
		int CountLeaves();
		int MaxDepth();

};


#endif
