#ifndef GREMLIN_GAME_H
#define GREMLIN_GAME_H

#include "common.h"
#include "sigslot.h"
#include "trimeshloader.h"
#include "Schedule.h"

#include <vector>
#include <memory>

// bullet forward declatations
class btDefaultCollisionConfiguration;
class btCollisionDispatcher;
class btBroadphaseInterface;
class btSequentialImpulseConstraintSolver;
class btDiscreteDynamicsWorld;
class btCollisionShape;
class btTriangleIndexVertexArray;
class btRigidBody;
class btMotionState;

typedef struct Team Team;
typedef struct player_t player_t;
class Game;

#define GAME_PLAYER_COUNT 64
#define GAME_BOMB_COUNT (GAME_PLAYER_COUNT * 5)
#define GAME_POINT_COUNT 50

struct player_t {
	uint16_t id;
	uint16_t status;
	double x, y, z;
	double rx, ry, rz, rw;
	double vx, vy, vz;
	Team *team;
	uint16_t points;
	std::auto_ptr<btMotionState> state;
	std::auto_ptr<btRigidBody> body;
};

struct bomb_t {
	uint8_t status;
	double x, y, z;
	double vx, vy, vz;
	double ttl;
};

struct point_t {
	uint8_t status;
	double x, y, z;
};

class Team {
public:
	uint16_t id;
	double x, y, z;
	float color[4];
	uint16_t points;
	uint16_t wins;
};

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

	std::vector<Team> teams;
	player_t player[GAME_PLAYER_COUNT];
	bomb_t bomb[GAME_BOMB_COUNT];
	point_t point[GAME_POINT_COUNT];
	int16_t max_player_id;
	int master;
	double updateTime;
	player_t *local_player;
	sigslot::signal3<double, double, double> ExplosionSignal;

	void setup();
	void reset();
	Team *team_with_least_players();
	player_t *spawnPlayer(Team *team);
	player_t *spawnPlayerWithId(Team *team, uint16_t id);
	Team *getTeam(uint16_t id);
	player_t *getPlayer(uint16_t id);
	bomb_t *getBomb(uint16_t index);
	void update_players(double dt);
	bomb_t *spawn_bomb();
	point_t *spawn_point();
	void update_bombs(double dt);
	void update_points(double dt);
	void update(double time, double dt);
	void set_master(int master);
	player_t *getFreePlayer();
	void explode_bomb(bomb_t *bomb);
	void update_point(point_t *point);
	size_t active_team_players(Team *team);

	tlTrimesh *levelMesh;
	tlTrimesh *shipMesh;

private:
	void setupLevel();
	void loadLevelShape();
	void loadShipShape();

	const std::auto_ptr<btDefaultCollisionConfiguration> collisionConfiguration;
	const std::auto_ptr<btCollisionDispatcher> dispatcher;
	const std::auto_ptr<btBroadphaseInterface> overlappingPairCache;
	const std::auto_ptr<btSequentialImpulseConstraintSolver> solver;
	const std::auto_ptr<btDiscreteDynamicsWorld> dynamicsWorld;
	std::auto_ptr<btTriangleIndexVertexArray> levelVertexArray;
	std::auto_ptr<btCollisionShape> levelShape;
	std::auto_ptr<btMotionState> levelState;
	std::auto_ptr<btRigidBody> levelBody;

	std::auto_ptr<btTriangleIndexVertexArray> shipVertexArray;
	std::auto_ptr<btCollisionShape> shipShape;

	Schedule slaveUpdate;
};

#endif
