#include "component_stat_display.h"

/* DEPENDENCIES: AnimationColorChange, GameObject, Text, Sprite, Physics */

static void _string_get(ComponentStatDisplay* self, ECS* ecs, char* string, u32* length);
static void _string_set(ComponentStatDisplay* self, ECS* ecs);
static void _position_get(ComponentStatDisplay* self, ECS* ecs, vec3 position);
static void _position_set(ComponentStatDisplay* self, ECS* ecs);
static void _stat_update(ComponentStatDisplay* self, ECS* ecs);
static void _visual_update(ComponentStatDisplay* self, ECS* ecs);
static bool _stat_compare(ComponentStatDisplay* self, ECS* ecs);
static void _active_set(ComponentStatDisplay* self, ECS* ecs);
static void _inactive_set(ComponentStatDisplay* self, ECS* ecs);

/* Once something is made inactive, this occurs. */
static void
_active_set(ComponentStatDisplay* self, ECS* ecs)
{
	ComponentAnimationColorChange* animationColorChange;

	animationColorChange = ecs_component_get(ecs, ECS_COMPONENT_ANIMATION_COLOR_CHANGE, self->component.id);

	animationColorChange->component.isDisabled = false;

	component_animation_color_change_init
	(
		animationColorChange,
		(f32*)COLOR_OPAQUE,
		(f32*)COLOR_TRANSPARENT,
		COMPONENT_STAT_DISPLAY_ANIMATION_COLOR_CHANGE_TIMER,
		ANIMATION_COLOR_CHANGE_MODE_RETURN
	);

	self->isInactive = false;
	self->activeTimer = COMPONENT_STAT_DISPLAY_INACTIVE_TIMER;
}

/* Once something is made active again, this occurs. */
static void
_inactive_set(ComponentStatDisplay* self, ECS* ecs)
{
	ComponentAnimationColorChange* animationColorChange;

	animationColorChange = ecs_component_get(ecs, ECS_COMPONENT_ANIMATION_COLOR_CHANGE, self->component.id);

	animationColorChange->component.isDisabled = false;

	component_animation_color_change_init
	(
		animationColorChange,
		(f32*)COLOR_TRANSPARENT,
		(f32*)COLOR_OPAQUE,
		COMPONENT_STAT_DISPLAY_ANIMATION_COLOR_CHANGE_TIMER,
		ANIMATION_COLOR_CHANGE_MODE_STICK
	);

	self->isInactive = true;
}

/* Checks if inactive. */
static void
_inactive_tick(ComponentStatDisplay* self, ECS* ecs)
{
	ComponentAnimationColorChange* animationColorChange;

	animationColorChange = ecs_component_get(ecs, ECS_COMPONENT_ANIMATION_COLOR_CHANGE, self->component.id);

	if (animationColorChange->isDone)
		animationColorChange->component.isDisabled = true;

	if (self->isInactive)
	{
		if (!_stat_compare(self, ecs))
			_active_set(self, ecs);
	}
	else
	{
		if (!_stat_compare(self, ecs))
			self->activeTimer = COMPONENT_STAT_DISPLAY_INACTIVE_TIMER;

		self->activeTimer--;

		if (self->activeTimer == 0)
			_inactive_set(self, ecs);
	}
}
/* Updates the previous stat component. */
static void
_stat_update(ComponentStatDisplay* self, ECS* ecs)
{
	Stat* stat;

	stat = (Stat*)ecs_component_get(ecs, self->type, self->gameObjectID);

	memcpy(&self->previousStat, stat, sizeof(Stat));
}

/* Compares stat components. */
static bool
_stat_compare(ComponentStatDisplay* self, ECS* ecs)
{
	Stat* stat;

	stat = (Stat*)ecs_component_get(ecs, self->type, self->gameObjectID);

	if (stat->value == self->previousStat.value)
		return true;

	return false;
}

/* Obtains the position. */
static void
_position_get(ComponentStatDisplay* self, ECS* ecs, vec3 position)
{
	ComponentPhysics* physics;

	physics = ecs_component_get(ecs, ECS_COMPONENT_PHYSICS, self->gameObjectID);

	glm_vec3_zero(position);

	position[0] = physics->position[0] + self->offset[0];
	position[1] = physics->position[1] + self->offset[1];
	position[2] = self->offset[2];
}

/* Sets the position. */
static void
_position_set(ComponentStatDisplay* self, ECS* ecs)
{
	ComponentText* text;
	ComponentSprite* streakSprite;
	ComponentSprite* iconSprite;
	vec3 position;
	Rectangle rectangle;
	
	text = ecs_component_get(ecs, ECS_COMPONENT_TEXT, self->component.id);
	streakSprite = ecs_component_get(ecs, ECS_COMPONENT_SPRITE, self->streakID);
	iconSprite = ecs_component_get(ecs, ECS_COMPONENT_SPRITE, self->iconID);

	component_text_rectangle_get(text, &rectangle);

	_position_get(self, ecs, position);

	glm_vec3_copy(position, streakSprite->position);
	glm_vec3_copy(position, iconSprite->position);

	iconSprite->position[0] = position[0] + COMPONENT_STAT_DISPLAY_ICON_X_OFFSET;
	
	streakSprite->position[2] = position[2] + COMPONENT_STAT_DISPLAY_STREAK_Z_OFFSET;
	iconSprite->position[2] = position[2] + COMPONENT_STAT_DISPLAY_ICON_Z_OFFSET;

	text->position[0] = streakSprite->position[0] + COMPONENT_STAT_DISPLAY_TEXT_X_OFFSET;
	text->position[1] = streakSprite->position[1] + COMPONENT_STAT_DISPLAY_TEXT_Y_OFFSET;;
	text->position[2] = position[2] + COMPONENT_STAT_DISPLAY_TEXT_Z_OFFSET;
}

/* Sets the string to the text component. */
static void
_string_set(ComponentStatDisplay* self, ECS* ecs)
{
	ComponentText* text;
	char string[COMPONENT_STAT_DISPLAY_TEXT_LENGTH_MAX];
	u32 length;

	text = ecs_component_get(ecs, ECS_COMPONENT_TEXT, self->component.id);

	_string_get(self, ecs, string, &length);

	component_text_string_set(text, string, length);
}

/* Obtains the string and its length. */
static void
_string_get(ComponentStatDisplay* self, ECS* ecs, char* string, u32* length)
{
	Stat* stat;

	stat = (Stat*)ecs_component_get(ecs, self->type, self->gameObjectID);

	snprintf
	(
		string, 
		COMPONENT_STAT_DISPLAY_TEXT_LENGTH_MAX,
		COMPONENT_STAT_DISPLAY_STRING_FORMAT,
		stat->value,
		stat->max
	);

	*length = strlen(string);
}

/* Updates the visuals. */
static void
_visual_update(ComponentStatDisplay* self, ECS* ecs)
{
	ComponentSprite* streakSprite;
	ComponentSprite* iconSprite;
	ComponentText* text;

	text = ecs_component_get(ecs, ECS_COMPONENT_TEXT, self->component.id);
	streakSprite = ecs_component_get(ecs, ECS_COMPONENT_SPRITE, self->streakID);
	iconSprite = ecs_component_get(ecs, ECS_COMPONENT_SPRITE, self->iconID);

	glm_vec4_copy(text->color, streakSprite->color);
	glm_vec4_copy(text->color, iconSprite->color);
}

/* Initializes a stat_display component. */
void
component_stat_display_init
(
	ComponentStatDisplay* self, 
	ECS* ecs,
	vec3 offset,
	ECSComponentType type,
	u32 gameObjectID,
	IconType icon
)
{
	ComponentText* text;
	ComponentSprite* streakSprite;
	ComponentAnimationColorChange* animationColorChange;
	char string[COMPONENT_STAT_DISPLAY_TEXT_LENGTH_MAX];
	vec3 position;
	u32 length;

	self->streakID = ecs_entity_add(ecs);
	self->iconID = ecs_entity_add(ecs);

	self->gameObjectID = gameObjectID;
	self->type = type;

	glm_vec3_copy(offset, self->offset);

	_stat_update(self, ecs);

	text = ecs_component_get(ecs, ECS_COMPONENT_TEXT, self->component.id);
	animationColorChange = ecs_component_get(ecs, ECS_COMPONENT_ANIMATION_COLOR_CHANGE, self->component.id);

	_string_get(self, ecs, string, &length);

	_position_get(self, ecs, position);

	component_text_init
	(
		text,
		&ecs->game->resources.fonts[COMPONENT_STAT_DISPLAY_TEXT_FONT],
		string,
		length,
		-1,
		position,
		COMPONENT_STAT_DISPLAY_TEXT_COLOR
	);

	entity_icon_init
	(
	 	ecs,
		self->iconID,
		position,
		(f32*)STAT_DISPLAY_ICON_SIZE,
		icon
	);

	entity_streak_init
	(
		ecs,
		self->streakID,
		position,
		(f32*)STAT_DISPLAY_STREAK_SIZE
	);

	component_text_string_set(text, string, length);

	animationColorChange->component.isDisabled = true;

	self->activeTimer = COMPONENT_STAT_DISPLAY_INACTIVE_TIMER;
}

/* Runs on adding a stat display component. */
void
component_stat_display_add(ComponentStatDisplay* self, ECS* ecs)
{
	ecs_component_add(ecs, ECS_COMPONENT_TEXT, self->component.id);
	ecs_component_add(ecs, ECS_COMPONENT_ANIMATION_COLOR_CHANGE, self->component.id);
}

/* Runs on adding a stat display component. */
void
component_stat_display_delete(ComponentStatDisplay* self, ECS* ecs)
{
	ecs_component_delete(ecs, ECS_COMPONENT_TEXT, self->component.id);
	ecs_component_delete(ecs, ECS_COMPONENT_ANIMATION_COLOR_CHANGE, self->component.id);

	ecs_entity_delete(ecs, self->iconID);
	ecs_entity_delete(ecs, self->streakID);
}

/* Ticks stat_display component. */
void 
component_stat_display_tick(ComponentStatDisplay* self, ECS* ecs)
{
	_inactive_tick(self, ecs);

	if (!_stat_compare(self, ecs))
		_string_set(self, ecs);

	_position_set(self, ecs);

	_stat_update(self, ecs);

	_visual_update(self, ecs);
}
