#include "gameCommon.h"
#include "util.h"
#include "PID.h"

#ifndef	ENTITY_H
#define ENTITY_H

enum {
	ENTITY_NONE = -1,
	ENTITY_ANTIFA,
	ENTITY_SOLDATO,
	ENTITY_CAPORALE,
	ENTITY_SERGENTE,
	ENTITY_MARESCIALLO,
	ENTITY_GENERALE,
	ENTITY_MUSSOLINI,
	ENTITY_GUIDED_MISSILE,
	ENTITY_MISSILE
};

#define ENTITY_TYPE_COUNT 9

typedef int8_t EntityType;
typedef int16_t EntityId; // Id in world.
typedef uint32_t EntityFingerprint;

// Callbacks.
typedef void (*EntityUpdateCb)(Game * game, Entity * entity);
typedef void (*EntityDrawCb)(Game * game, Entity * entity);

// Acceleration indeed hehehe.
typedef struct EntityAcceleration {
	Vector3 rotation;
	float speedUp;
	float speedDown;
} EntityAcceleration;

float accelerateValue(float value, float lastValue, float up, float down);
Vector3 accelerateVector3(Vector3 value, Vector3 lastValue, Vector3 up, Vector3 down);

typedef struct EntityVelocity {
	Vector3 velocity;
	AxisAngle angularVelocity;
	Vector3 stick; // Pilot control stick.
	float speed; // Somewhat general use (:
} EntityVelocity;

EntityVelocity entityVelocityIdentity();

typedef struct EntityCollisionMesh {
	size_t triangleCount;
	Triangle3D * triangles;
	Vector3 * normals;
} EntityCollisionMesh;

typedef struct EntityCollisionModel {
	size_t meshCount;
	EntityCollisionMesh * meshes;
} EntityCollisionModel;

EntityCollisionModel entityCreateCollisionModel(Model model);
void entityFreeCollisionModel(EntityCollisionModel model);

// Only use if both collision models came from the same model.
void entityTransformCollisionModel(Entity * entity);

// Checks if collision model will need to be transformed.
void entityCheckTransformedCollisionModel(Entity * entity);

// This fucker hit something.
typedef struct EntityCollision {
	bool hit;
	EntityId fromId;
	EntityFingerprint fromFingerprint;
} EntityCollision;

// Used for hanlding the soldato follower and leader thing.
typedef struct EntityFollow {
	EntityId leaderId;
	EntityFingerprint leaderFingerprint;

	EntityId followerId;
	EntityFingerprint followerFingerprint;
} EntityFollow;

// Health stuff.
#define ENTITY_MIN_HEALTH 0.0
#define ENTITY_MAX_HEALTH 1.0

// This fucker is a entity.
typedef struct Entity {
	EntityId id;
	EntityFingerprint fingerprint;
	EntityType type;

	Model * model;
	float radius; // Used for quick collision detection.
	
	EntityCollisionModel collisionModel;
	EntityCollisionModel transformedCollisionModel;
	// Use for checking if model been transformed indeed.
	bool collisionModelTransformed;

	Vector3 position;
	Quaternion rotation;

	Vector3 lastPosition;
	Quaternion lastRotation;

	EntityVelocity velocity;
	EntityVelocity lastVelocity;

	bool useAcceleration;
	EntityAcceleration acceleration;

	EntityUpdateCb updateCb;
	EntityDrawCb drawCb;

	EntityFollow follow;

	// Health is a percent from 1.0 to 0.0.
	float health;

	EntityCollision collision;

	// Used for whatever.
	void * data;
} Entity;

typedef void (*EntityInitCb)(Entity * entity, Game * game);
typedef void (*EntityCloseCb)(Entity * entity);

// Info for each entity type.
typedef struct EntityTypeInfo {
	EntityInitCb initCb;
	EntityCloseCb closeCb;
	EntityUpdateCb updateCb;
	EntityDrawCb drawCb;
} EntityTypeInfo;

const extern EntityTypeInfo entityTypeInfo[ENTITY_TYPE_COUNT];

// Do I need a fucking comment?
Entity createEntity(EntityType type, Game * game);
void closeEntity(Entity * entity);

void setEntityRadius(Entity * entity); // Uses model to set radius;
bool checkEntityCollision(Entity * entity1, Entity * entity2);

RayCollision traceRayToEntity(Entity entity, Ray ray);
RayCollision traceRayToEntityRadius(Entity entity, Ray ray, float scale);

// Helper functions for updating, drawing...
void entityDraw(Entity * entity);
void entityUpdatePosition(Entity * entity);
void entityUpdateRotation(Entity * entity);
void entityUpdateLastValues(Entity * entity); // Should be at top of update function.

void entityJoystickControl(Entity * entity, Vector3 stick, float speed);

enum {
	ENTITY_FLY_TO_POINT_PID,
	ENTITY_FLY_TO_POINT_BANG_BANG
};

// Shit for fly to point.
typedef struct EntityFlyToPointInfo {
	union {
		PID speedPID;

		struct {
			float speed;
			float stopAt;
		} bangbang;
	} controller;

	uint8_t controlType;
	float rotationSpeed; // 0.0 to not use.
	bool applyRotation;
} EntityFlyToPointInfo;

void entityFlyToPoint(Entity * entity, Vector3 point, EntityFlyToPointInfo * info);

#endif