#ifndef _OBJECTS_H

#include <stdio.h>			// Header File For Standard Input/Output
#include <GL/gl.h>
#include <GL/glu.h>
#include <SDL/SDL.h>
#ifdef __APPLE__
#include <SDL_image/SDL_image.h>
#else
#include <SDL/SDL_image.h>
#endif
#include <string>
#include <iostream>
#include <fstream>
#include <cmath>
#include <cassert>

#include <list>
#include <map>

//#include "terrain.h"
#include "utility.h"
#include "quat.h"
#include "terrain.h"
#include "camera.h"
#include "model.h"

#include "globals.h"

#define TRIANGLES_PER_BBOX 1

#define COLLIDE_AND_DRIVE_TOGETHER true

class OBJECTMODEL
{
public:
	JOEMODEL jmodel;
	string name;
	OBJECTMODEL * next;
	bool fullbright;
	bool skybox;
};

class OBJECTNODE
{
public:
	VERTEX pos;
	bool driveable;
	bool cancollide;
	OBJECTNODE * next;
	QUATERNION dir;
	OBJECTMODEL * model;

	OBJECTNODE();
};

class OBJCOLNODE
{
public:
	OBJCOLNODE();
	OBJCOLNODE(const OBJCOLNODE & other);
	OBJCOLNODE& operator= (const OBJCOLNODE &other);
	bool operator==(const OBJCOLNODE & other);
	
//private:
	OBJECTNODE * object;
	short vertexIndex[3];
};

class OBJCOLBRANCH
{
public:
	OBJCOLBRANCH();
	void DeleteChildren();
	AABB bbox;
	OBJCOLBRANCH * left;
	OBJCOLBRANCH * right;
	list <OBJCOLNODE *> leaves;
};

class OBJECTCOLLISION
{
public:
	~OBJECTCOLLISION();
	
	void AddColNode(OBJECTNODE * newobject, short * newvi);
	//bool Collide(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest, VERTEX & normal);
	bool CollideDriveable(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest, VERTEX & normal);
	bool CollideAABB(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest, VERTEX & normal, float seglen);
	bool CollideAABB_double(VERTEXD origin, VERTEXD direction, VERTEXD &outtri, bool closest, VERTEXD & normal, double seglen);
	bool CollideModelAABB(VERTEX * modelverts, int numfaces, AABB modelbbox, VERTEX & outtri, bool closest, VERTEX & normal, float & depth);
	void GenerateCollisionTree();
	void Clear();

private:
	list <OBJCOLNODE> colnodes;
	list <OBJCOLNODE> drvnodes;

	OBJCOLBRANCH coltree;
	void GenerateBranches(OBJCOLBRANCH * branch);
	bool CollideBranch(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest, OBJCOLBRANCH * branch, VERTEX & normal, float seglen);
	bool CollideBranch_double(VERTEXD origin, VERTEXD direction, VERTEXD &outtri, bool closest, OBJCOLBRANCH * branch, VERTEXD & normal, double seglen);
	bool CollideBranchModel(VERTEX * modelverts, int numfaces, AABB & modelbbox, VERTEX & outtri, bool closest, OBJCOLBRANCH * branch, VERTEX & normal, float & depth);
};

class OBJECTS
{
private:
	ofstream error_log;
	OBJECTMODEL * model_list;
	void delmodel();

	OBJECTNODE * object_list;
	void delobject();

	void DrawObject(OBJECTNODE * object);

	OBJECTMODEL * AddModel(string modelname, string texname, bool mip, bool fullbright, bool skybox);

	string path;

	OBJECTCOLLISION collision;

	map <string, GLuint> texture_db;
	
public:
	OBJECTS();
	~OBJECTS();
	void Draw();
	OBJECTNODE * Add(VERTEX pos, float rotation, string modelname, string texname, bool mip, bool fullbright, bool skybox, bool drv, bool col);
	void DeleteAll();

	bool Collide(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest, VERTEX & normal, float seglen);
	bool CollideD(VERTEXD origin, VERTEXD direction, VERTEXD &outtri, bool closest, VERTEXD & normal, double seglen);
	bool CollideDriveable(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest, VERTEX & normal);
	//bool Collide(VERTEX origin, VERTEX direction, VERTEX &outtri, bool closest, OBJECTNODE * &collideobject);

	bool CollideModel(VERTEX * modelverts, int numfaces, AABB bbox, VERTEX & outtri, bool closest, VERTEX & normal, float & depth);

	void LoadObjectsFromFolder(string objectpath);
	bool GetCollideAndDriveTogether() {return COLLIDE_AND_DRIVE_TOGETHER;}
};

#define _OBJECTS_H
#endif
