#include "state.h"

static void _state_set(State* self, StateType type);
static void _state_level_tick(State* self, LevelType type);

static void
_state_level_tick(State* self, LevelType type)
{
	level_tick(&self->states.level);

	if (self->states.level.isPaused)
	{
		if (control_released(self->ecs->control, CONTROL_RETRY))
			_state_set(self, self->type);

		if (control_released(self->ecs->control, CONTROL_ESCAPE))
		{
			level_unpause(&self->states.level);
			_state_set(self, STATE_TITLE);
		}
	}

	if (self->states.level.isFinished)
	{
		if (self->states.level.medal > LEVEL_MEDAL_NONE)
			self->levelData[type].status = LEVEL_STATUS_LOCKED + self->states.level.medal;

		self->levelData[type].time = self->states.level.timeToMedal;
		self->levelData[type].score = self->states.level.score;

		if (self->states.level.isComplete && type < LEVEL_FIVE)
		{
			if (self->levelData[type + 1].status == LEVEL_STATUS_LOCKED)
				self->levelData[type + 1].status = LEVEL_STATUS_UNLOCKED;
		}

		if (type == LEVEL_FIVE && self->states.level.isComplete)
			_state_set(self, STATE_CUTSCENE_FINAL);
		else
			_state_set(self, STATE_TITLE);
	}
}

static void
_state_set(State* self, StateType type)
{
	state_free(self);

	self->type = type;

	for (s32 i = 0; i < RENDERER_BUFFER_COUNT; i++)
		postprocessing_init(&self->ecs->postprocessing[i], OPAQUE, TRANSPARENT);

	switch (self->type)
	{
		case STATE_TITLE:
			title_init(&self->states.title, self->ecs, (LevelData*)self->levelData, LEVEL_COUNT);
			break;
		case STATE_CUTSCENE_ONE:
			cutscene_init(&self->states.cutscene, self->ecs, CUTSCENE_ONE);
			break;
		case STATE_CUTSCENE_TWO:
			cutscene_init(&self->states.cutscene, self->ecs, CUTSCENE_TWO);
			break;
		case STATE_CUTSCENE_THREE:
			cutscene_init(&self->states.cutscene, self->ecs, CUTSCENE_THREE);
			break;
		case STATE_CUTSCENE_FOUR:
			cutscene_init(&self->states.cutscene, self->ecs, CUTSCENE_FOUR);
			break;
		case STATE_CUTSCENE_FIVE:
			cutscene_init(&self->states.cutscene, self->ecs, CUTSCENE_FIVE);
			break;
		case STATE_CUTSCENE_FINAL:
			cutscene_init(&self->states.cutscene, self->ecs, CUTSCENE_FINAL);
			break;
		case STATE_ENDING:
			ending_init(&self->states.ending, self->ecs, ENDING_ONE);
			break;
		case STATE_ENDING_TWO:
			ending_init(&self->states.ending, self->ecs, ENDING_TWO);
	break;
		case STATE_ENDING_THREE:
			ending_init(&self->states.ending, self->ecs, ENDING_THREE);
			break;
		case STATE_LEVEL_ONE:
			level_init(&self->states.level, self->ecs, LEVEL_SETTINGS[LEVEL_ONE], LEVEL_ONE);
			break;
		case STATE_LEVEL_TWO:
			level_init(&self->states.level, self->ecs, LEVEL_SETTINGS[LEVEL_TWO], LEVEL_TWO);
			break;
		case STATE_LEVEL_THREE:
			level_init(&self->states.level, self->ecs, LEVEL_SETTINGS[LEVEL_THREE], LEVEL_THREE);
			break;
		case STATE_LEVEL_FOUR:
			level_init(&self->states.level, self->ecs, LEVEL_SETTINGS[LEVEL_FOUR], LEVEL_FOUR);
			break;
		case STATE_LEVEL_FIVE:
			level_init(&self->states.level, self->ecs, LEVEL_SETTINGS[LEVEL_FIVE], LEVEL_FIVE);
			break;
		default:
			break;
	}
}

void
state_init(State* self, ECS* ecs, StateType type)
{
	memset(self, '\0', sizeof(State));

	self->ecs = ecs;

	memcpy(self->levelData, LEVEL_DATA_DEFAULT, sizeof(LEVEL_DATA_DEFAULT));

	_state_set(self, type);
}

void
state_free(State* self)
{
	switch (self->type)
	{
		case STATE_TITLE:
			title_free(&self->states.title);
			break;
		case STATE_LEVEL_ONE:
		case STATE_LEVEL_TWO:
		case STATE_LEVEL_THREE:
		case STATE_LEVEL_FOUR:
		case STATE_LEVEL_FIVE:
			level_free(&self->states.level);
			break;
		case STATE_CUTSCENE_ONE:
		case STATE_CUTSCENE_TWO:
		case STATE_CUTSCENE_THREE:
		case STATE_CUTSCENE_FOUR:
		case STATE_CUTSCENE_FIVE:
		case STATE_CUTSCENE_FINAL:
			cutscene_free(&self->states.cutscene);
			break;
		case STATE_ENDING:
		case STATE_ENDING_TWO:
		case STATE_ENDING_THREE:
			ending_free(&self->states.ending);
		default:
			break;
	}
	ecs_clear(self->ecs);
}

void
state_change(State* self, StateType type)
{
	self->setType = type;
}

void
state_tick(State* self)
{
	u32 endingPoints;

	endingPoints = 0;

	if (self->isChanging)
	{
		self->isChanging = false;
		state_free(self);

		memset(&self->states, '\0', sizeof(self->states));

		_state_set(self, self->setType);
		return;
	}

	switch (self->type)
	{
		case STATE_LEVEL_ONE:
			_state_level_tick(self, LEVEL_ONE);
			break;
		case STATE_LEVEL_TWO:
			_state_level_tick(self, LEVEL_TWO);
			break;
		case STATE_LEVEL_THREE:
			_state_level_tick(self, LEVEL_THREE);
			break;
		case STATE_LEVEL_FOUR:
			_state_level_tick(self, LEVEL_FOUR);
			break;
		case STATE_LEVEL_FIVE:
			_state_level_tick(self, LEVEL_FIVE);
			break;
		case STATE_TITLE:
			title_tick(&self->states.title);

			if (self->states.title.isLevelSelected)
				_state_set(self, STATE_CUTSCENE_ONE + self->states.title.levelSelected);

			break;
		case STATE_CUTSCENE_ONE:
			cutscene_tick(&self->states.cutscene);
			
			if (self->states.cutscene.isFinished)
				_state_set(self, STATE_LEVEL_ONE);
			
			break;
		case STATE_CUTSCENE_TWO:
			cutscene_tick(&self->states.cutscene);
			
			if (self->states.cutscene.isFinished)
				_state_set(self, STATE_LEVEL_TWO);
			
			break;
		case STATE_CUTSCENE_THREE:
			cutscene_tick(&self->states.cutscene);
			
			if (self->states.cutscene.isFinished)
				_state_set(self, STATE_LEVEL_THREE);
			
			break;
		case STATE_CUTSCENE_FOUR:
			cutscene_tick(&self->states.cutscene);
			
			if (self->states.cutscene.isFinished)
				_state_set(self, STATE_LEVEL_FOUR);
			
			break;
		case STATE_CUTSCENE_FIVE:
			cutscene_tick(&self->states.cutscene);
			
			if (self->states.cutscene.isFinished)
				_state_set(self, STATE_LEVEL_FIVE);
			
			break;
		case STATE_CUTSCENE_FINAL:
			cutscene_tick(&self->states.cutscene);
			
			if (self->states.cutscene.isFinished)
			{
				for (s32 i = 0; i < LEVEL_COUNT; i++)
					endingPoints += self->levelData[i].status;

				if (endingPoints >= LEVEL_STATUS_GOLD * LEVEL_COUNT)
					_state_set(self, STATE_ENDING_THREE);
				else if (endingPoints >= (LEVEL_STATUS_SILVER * LEVEL_COUNT))
					_state_set(self, STATE_ENDING_TWO);
				else
					_state_set(self, STATE_ENDING);
			}

			break;
		case STATE_ENDING:
		case STATE_ENDING_TWO:
		case STATE_ENDING_THREE:
			ending_tick(&self->states.ending);

			if (self->states.ending.isFinished)
				_state_set(self, STATE_TITLE);
			break;
		default:
			break;
	}
}