//S.U.C.C.
//Simple Unfeatured Collision Class

//a simple collision system that assumes the entire world is made up of world oriented bounding boxes.
//colliding vectors return assuming Y is up,  as is the default in Ogre 

//created by metaldev.  2007
//the license for using this software means you must  keep this paragraph intact on any copies or modifications of this class.
//Otherwise, there are no limitations on the use of this free open source software,  use for anything you like!  Commercial or not.
//for questions or support use the forums at www.lfagames.com or www.ogre3d.org


#ifndef LFA_COLLISION_MANAGER_H
#define LFA_COLLISION_MANAGER_H

#include "common.h"
#include <OgreString.h>  //std string
#include <vector>


// Forward declarations
class TiXmlDocument;
class TiXmlElement;

namespace LFA
{

	struct collisionBox
	{
		std::string name;	//name of the collision cube
		std::string var;		//var of the collision cube
		float xmin;
		float ymin;
		float zmin;
		float xmax;
		float ymax;
		float zmax;
	};	

	struct collisionBranch : collisionBox	//intended to be used as a bounding box for groups of boxes to use in culling out large parts of the world when collision checking.
	{
		std::vector<collisionBox> colBoxes;
	};	


	struct collisionHit
	{
		std::string name;				//name of the collision cube we collided with
		std::string var;					//var of the collision cube we collided with
		float posX;
		float posY;
		float posZ;
		float distance;					//distance from the first given point, represented as t.  this is NOT unit distance,  its used for sorting the hits in the array.
		Ogre::Quaternion qVector;	//if the hit was generated from a line collision,  this will contain a normal facing a way from the surface.
	};	

	class collisionManager
		{
		public:
		collisionManager();
		~collisionManager();

		void loadCollisionFile( const Ogre::String &collisionFileName, const Ogre::String &groupName);
		
		//COLLISION DETECTION
		//collide point with collisions from loaded xml
		std::vector<collisionHit> pointCollide(Ogre::Vector3 position);
		std::vector<collisionHit> pointCollide(float &x, float &y, float &z);	

		//collide box with collisions from loaded xml
		std::vector<collisionBox> boxCollide(collisionBox &cBox);
		std::vector<collisionBox> boxCollide(float &xmax, float &ymax, float &zmax, float &xmin, float &ymin, float &zmin);		

		//collide a line with collisions from loaded xml
		std::vector<collisionHit> lineCollide(Ogre::Vector3 position1, Ogre::Vector3 position2);
		std::vector<collisionHit> lineCollide(float &x1, float &y1, float &z1, float &x2, float &y2, float &z2);	

		//collide a given point with a given box
		bool pointVsBox (Ogre::Vector3 position, collisionBox &cBox);
		bool pointVsBox (float &x, float &y, float &z, collisionBox &cBox);
		bool pointVsBox (float &x, float &y, float &z, float &xmax, float &ymax, float &zmax, float &xmin, float &ymin, float &zmin);	

		//collide given box with another given box
		bool boxVsBox (collisionBox &cBox1, collisionBox &cBox2);
		bool boxVsBox (collisionBox &cBox, float &xmax, float &ymax, float &zmax, float &xmin, float &ymin, float &zmin);
		bool boxVsBox (float &xmax1, float &ymax1, float &zmax1, float &xmin1, float &ymin1, float &zmin1, float &xmax2, float &ymax2, float &zmax2, float &xmin2, float &ymin2, float &zmin2);

		//bool cylVsBox ();
		//bool cylVsPoint();
		//bool cylVsCyl();
		//std::vector<collisionHit> lineVsCyl();

		//collide a given ray with a given box
		std::vector<collisionHit> rayVsBox (Ogre::Vector3 position1, Ogre::Vector3 position2, collisionBox &cBox); 
		std::vector<collisionHit> rayVsBox (float &x1, float &y1, float &z1, float &x2, float &y2, float &z2, collisionBox &cBox); 
		std::vector<collisionHit> rayVsBox (float &x1, float &y1, float &z1, float &x2, float &y2, float &z2, float &xmax, float &ymax, float &zmax, float &xmin, float &ymin, float &zmin);

		void orderCollisionHitsByDistance(std::vector<collisionHit> *hits); 
		//convert 2 points into a collisionBox
		collisionBox rayToBox(float &x1, float &y1, float &z1, float &x2, float &y2, float &z2);
		void eulerToQuat(float &roll, float &pitch, float &yaw, Ogre::Quaternion * quat);

		private:
			std::vector<collisionBranch> *mCollision; //root element of our currently stored collision		
			bool oneDimentionalTest( float &min1, float &max1,  float &min2, float &max2);		

			std::string getAttrib(TiXmlElement *XMLNode, const std::string &parameter, const std::string &defaultValue = "");
			Ogre::Real getAttribReal(TiXmlElement *XMLNode, const std::string &parameter, Ogre::Real defaultValue = 0);
		};

}


#endif //LFA_COLLISION_MANAGER_H