#include "cameras.h"
#include "game.h"
#include "world.h"
#include "entitiesInclude.h"

// First person camera indeed.
void initFirstPersonCamera(Game * game, Camera3D * camera) {
	*camera = (Camera3D){
		.fovy = 90.0,
		.projection = CAMERA_PERSPECTIVE
	};
}

void updateFirstPersonCamera(Game * game, Camera3D * camera) {
	Entity * player = getEntityFromWorld(game->world, 0);
	Vector3 direction = Vector3RotateByQuaternion((Vector3){0.0, 0.0, 1.0}, player->rotation);

	camera->position = Vector3Add(player->position, Vector3Scale(direction, FIRST_PERSON_CAMERA_DISTANCE));
	camera->target = Vector3Add(camera->position, direction);
	camera->up = Vector3RotateByQuaternion((Vector3){0.0, 1.0, 0.0}, player->rotation);
}

// Third person hehehe.
void initThirdPersonCamera(Game * game, Camera3D * camera) {
	*camera = (Camera3D){
		.fovy = 90.0,
		.projection = CAMERA_PERSPECTIVE
	};
}

void updateThirdPersonCamera(Game * game, Camera3D * camera) {
	Entity * player = getEntityFromWorld(game->world, 0);
	Vector3 direction = Vector3RotateByQuaternion(THIRD_PERSON_CAMERA_DISTANCE, player->rotation);
	camera->position = Vector3Add(player->position, direction);

	camera->target = player->position;
	camera->up = Vector3RotateByQuaternion((Vector3){0.0, 1.0, 0.0}, player->rotation);
}

// Zoom camera indeed hehehehehehe.
void initZoomCamera(Game * game, Camera3D * camera) {
	*camera = (Camera3D){
		.fovy = 12.0,
		.projection = CAMERA_PERSPECTIVE
	};
}

void updateZoomCamera(Game * game, Camera3D * camera) {
	Entity * player = getEntityFromWorld(game->world, 0);
	AntifaShip * data = (AntifaShip*)player->data;

	Vector3 direction;

	// Get direction. Aim with ship or target on target entity.
	if (data->doAutoTarget)
		direction = data->gunTarget;
	else
		direction = Vector3RotateByQuaternion((Vector3){0.0, 0.0, 1.0}, player->rotation);

	camera->position = Vector3Add(player->position, Vector3Scale(direction, FIRST_PERSON_CAMERA_DISTANCE));
	camera->target = Vector3Add(camera->position, direction);
	camera->up = Vector3RotateByQuaternion((Vector3){0.0, 1.0, 0.0}, player->rotation);
}

// KILL THE BUGS!!!
void initDebugCamera(Game * game, Camera3D * camera) {
	*camera = (Camera3D){
		.fovy = 120.0,
		.projection = CAMERA_PERSPECTIVE,
		.position = DEBUG_CAMERA_POSITION,
		.up = (Vector3){0.0, 1.0, 0.0}
	};
}

void updateDebugCamera(Game * game, Camera3D * camera) {
	Entity * player = getEntityFromWorld(game->world, 0);
	camera->target = player->position;
}

// Callbacks indeed.
const CameraInitCb cameraInitCallbacks[CAMERA_COUNT] = {
	initFirstPersonCamera,
	initThirdPersonCamera,
	initZoomCamera,
	initDebugCamera
};

const CameraCb cameraCallbacks[CAMERA_COUNT] = {
	updateFirstPersonCamera,
	updateThirdPersonCamera,
	updateZoomCamera,
	updateDebugCamera
};

void initCameras(Game * game, Cameras cameras) {
	int i;

	for (i = 0; i < CAMERA_COUNT; ++i)
		cameraInitCallbacks[i](game, &cameras[i]);
}

void runCameraUpdate(Game * game, Cameras cameras, CameraId id) {
	cameraCallbacks[id](game, &cameras[id]);
}