#include "demo.h"
#include <SDL2/SDL_events.h> // for SDL_PollEvent, SDL_Event
#include <SDL2/SDL_rect.h>	 // for SDL_Rect
#include <SDL2/SDL_timer.h>	 // for SDL_GetTicks
#include <iostream>			 // for basic_ostream, operator<<, cout, endl
#include "asset.h"			 // for Asset
#include "debug.h"			 // for Debug
#include "defines.h"		 // for BLOCK, PLAY_AREA_WIDTH, GAMECANVAS_CENT...
#include "global_events.h"	 // for check
#include "global_inputs.h"	 // for check
#include "input.h"			 // for Input
#include "item_tracker.h"	 // for ItemTracker
#include "options.h"		 // for Options, options, OptionsVideo, Section...
#include "resource.h"		 // for Resource
#include "room.h"			 // for Room
#include "screen.h"			 // for Screen
#include "text.h"			 // for Text, TEXT_CENTER, TEXT_COLOR
#include "utils.h"			 // for Color, stringToColor, colorAreEqual

// Constructor
Demo::Demo()
	: board_(std::make_shared<ScoreboardData>())
{
	// Inicia algunas variables
	board_->ini_clock = SDL_GetTicks();
	rooms_.push_back("04.room");
	rooms_.push_back("54.room");
	rooms_.push_back("20.room");
	rooms_.push_back("09.room");
	rooms_.push_back("05.room");
	rooms_.push_back("11.room");
	rooms_.push_back("31.room");
	rooms_.push_back("44.room");

	room_index_ = 0;
	current_room_ = rooms_[room_index_];

	// Crea los objetos
	ItemTracker::init();
	scoreboard_ = std::make_shared<Scoreboard>(board_);
	room_ = std::make_shared<Room>(current_room_, board_);

	// Inicializa el resto de variables
	counter_ = 0;
	room_time_ = 400;
	ticks_ = 0;
	board_->lives = 9;
	board_->items = 0;
	board_->rooms = 1;
	board_->jail_is_open = false;
	board_->music = true;
	setScoreBoardColor();

	options.section.section = Section::DEMO;
	options.section.subsection = Subsection::NONE;
}

// Destructor
Demo::~Demo()
{
	ItemTracker::destroy();
}

// Comprueba los eventos de la cola
void Demo::checkEvents()
{
	SDL_Event event;
	while (SDL_PollEvent(&event))
	{
		globalEvents::check(event);
	}
}

// Comprueba las entradas
void Demo::checkInput()
{
	globalInputs::check();
}

// Bucle para el juego
void Demo::run()
{
	while (options.section.section == Section::DEMO)
	{
		update();
		checkEvents();
		render();
	}
}

// Actualiza el juego, las variables, comprueba la entrada, etc.
void Demo::update()
{
	// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
	if (SDL_GetTicks() - ticks_ > GAME_SPEED)
	{
		// Actualiza el contador de ticks
		ticks_ = SDL_GetTicks();

		// Comprueba las entradas
		checkInput();

		// Actualiza los objetos
		room_->update();
		scoreboard_->update();
		checkRoomChange();

		Screen::get()->update();
	}
}

// Pinta los objetos en pantalla
void Demo::render()
{
	// Prepara para dibujar el frame
	Screen::get()->start();

	// Dibuja los elementos del juego en orden
	room_->renderMap();
	room_->renderEnemies();
	room_->renderItems();
	renderRoomName();
	scoreboard_->render();

	// Actualiza la pantalla
	Screen::get()->render();
}

// Escribe el nombre de la pantalla
void Demo::renderRoomName()
{
	// Texto en el centro de la pantalla
	SDL_Rect rect = {0, 16 * BLOCK, PLAY_AREA_WIDTH, BLOCK * 2};
	Color color = stringToColor(options.video.palette, "white");
	SDL_SetRenderDrawColor(Screen::get()->getRenderer(), color.r, color.g, color.b, 0xFF);
	SDL_RenderFillRect(Screen::get()->getRenderer(), &rect);

	Resource::get()->getText("smb2")->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, 16 * 8 + 4, room_->getName(), 1, room_->getBGColor());
}

// Cambia de habitación
bool Demo::changeRoom(const std::string &room_path)
{
	// En las habitaciones los limites tienen la cadena del fichero o un 0 en caso de no limitar con nada
	if (room_path != "0")
	{
		// Verifica que exista el fichero que se va a cargar
		if (Asset::get()->get(room_path) != "")
		{
			// Crea un objeto habitación a partir del fichero
			room_ = std::make_shared<Room>(room_path, board_);

			// Pone el color del marcador en función del color del borde de la habitación
			setScoreBoardColor();

			return true;
		}
	}

	return false;
}

// Comprueba si se ha de cambiar de habitación
void Demo::checkRoomChange()
{
	counter_++;
	if (counter_ == room_time_)
	{
		counter_ = 0;
		room_index_++;
		if (room_index_ == (int)rooms_.size())
		{
			options.section.section = Section::LOGO;
			options.section.subsection = Subsection::LOGO_TO_TITLE;
		}
		else
		{
			changeRoom(rooms_[room_index_]);
		}
	}
}

// Pone el color del marcador en función del color del borde de la habitación
void Demo::setScoreBoardColor()
{
	// Obtiene el color del borde
	const Color color = room_->getBorderColor();

	// Si el color es negro lo cambia a blanco
	const Color black_color = stringToColor(options.video.palette, "black");
	board_->color = colorAreEqual(color, black_color) ? stringToColor(options.video.palette, "white") : color;

	// Si el color es negro brillante lo cambia a blanco
	const Color bright_blac_color = stringToColor(options.video.palette, "bright_black");
	board_->color = colorAreEqual(color, bright_blac_color) ? stringToColor(options.video.palette, "white") : color;
}