#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
/*****************************************************************************
 * OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
 *
 * OpenRCT2 is the work of many authors, a full list can be found in contributors.md
 * For more information, visit https://github.com/OpenRCT2/OpenRCT2
 *
 * OpenRCT2 is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * A full copy of the GNU General Public License can be found in licence.txt
 *****************************************************************************/
#pragma endregion

#pragma warning(disable : 4996) // GetVersionExA deprecated

#include <time.h>
#include "addresses.h"
#include "audio/audio.h"
#include "audio/mixer.h"
#include "config.h"
#include "drawing/drawing.h"
#include "editor.h"
#include "game.h"
#include "input.h"
#include "interface/chat.h"
#include "interface/console.h"
#include "interface/viewport.h"
#include "intro.h"
#include "localisation/date.h"
#include "localisation/localisation.h"
#include "management/news_item.h"
#include "network/network.h"
#include "network/twitch.h"
#include "object.h"
#include "openrct2.h"
#include "peep/staff.h"
#include "platform/platform.h"
#include "rct1.h"
#include "ride/ride.h"
#include "ride/track.h"
#include "ride/track_design.h"
#include "scenario.h"
#include "title.h"
#include "util/util.h"
#include "world/map.h"
#include "world/park.h"
#include "world/climate.h"
#include "world/scenery.h"
#include "world/sprite.h"

// rct2: 0x0097F67C
const char * const RCT2FilePaths[PATH_ID_END] = {
	"Data\\g1.dat",
	"Data\\plugin.dat",
	"Data\\css1.dat",
	"Data\\css2.dat",
	"Data\\css4.dat",
	"Data\\css5.dat",
	"Data\\css6.dat",
	"Data\\css7.dat",
	"Data\\css8.dat",
	"Data\\css9.dat",
	"Data\\css11.dat",
	"Data\\css12.dat",
	"Data\\css13.dat",
	"Data\\css14.dat",
	"Data\\css15.dat",
	"Data\\css3.dat",
	"Data\\css17.dat",
	"Data\\css18.dat",
	"Data\\css19.dat",
	"Data\\css20.dat",
	"Data\\css21.dat",
	"Data\\css22.dat",
	"Saved Games\\scores.dat",
	"Data\\css23.dat",
	"Data\\css24.dat",
	"Data\\css25.dat",
	"Data\\css26.dat",
	"Data\\css27.dat",
	"Data\\css28.dat",
	"Data\\css29.dat",
	"Data\\css30.dat",
	"Data\\css31.dat",
	"Data\\css32.dat",
	"Data\\css33.dat",
	"Data\\css34.dat",
	"Data\\css35.dat",
	"Data\\css36.dat",
	"Data\\css37.dat",
	"Data\\css38.dat",
	"Data\\CUSTOM1.WAV",
	"Data\\CUSTOM2.WAV",
	"Data\\css39.dat",
	"Data\\css40.dat",
	"Data\\css41.dat",
	"Scenarios\\Six Flags Magic Mountain.SC6",
	"Data\\css42.dat",
	"Data\\css43.dat",
	"Data\\css44.dat",
	"Data\\css45.dat",
	"Data\\css46.dat",
	"Data\\css50.dat"
};

uint32 gCurrentDrawCount = 0;

uint8 gScreenFlags;
uint32 gScreenAge;
uint8 gSavePromptMode;
sint32 gScreenWidth;
sint32 gScreenHeight;

typedef struct tm tm_t;

void print_launch_information();

int rct2_init_directories();
int rct2_startup_checks();

static void rct2_draw_fps();

void rct2_quit()
{
	gSavePromptMode = PM_QUIT;
	window_save_prompt_open();
}

void rct2_dispose()
{
	gfx_unload_g2();
	gfx_unload_g1();
	object_unload_all();
}

int rct2_init()
{
	log_verbose("initialising game");

	gScenarioTicks = 0;
	util_srand((unsigned int)time(0));
	if (!rct2_init_directories())
		return 0;

	if (!rct2_startup_checks())
		return 0;

	config_reset_shortcut_keys();
	config_shortcut_keys_load();
	gInputPlaceObjectModifier = PLACE_OBJECT_MODIFIER_NONE;
	// config_load();

	gfx_load_g1();
	gfx_load_g2();

	object_list_load();
	scenario_load_list();
	track_design_index_create();

	font_sprite_initialise_characters();
	if (!gOpenRCT2Headless) {
		platform_init();
		audio_init_ride_sounds_and_info();
	}
	viewport_init_all();
	news_item_init_queue();
	reset_park_entrances();
	user_string_clear_all();
	reset_sprite_list();
	ride_init_all();
	window_guest_list_init_vars_a();
	staff_reset_modes();
	map_init(150);
	park_init();
	if (!gOpenRCT2Headless)
		window_title_menu_open();
	date_reset();
	climate_reset(CLIMATE_COOL_AND_WET);
	scenery_set_default_placement_configuration();
	window_new_ride_init_vars();
	window_guest_list_init_vars_b();
	window_staff_list_init_vars();

	if (!gOpenRCT2Headless) {
		title_load();

		gfx_clear(&gScreenDPI, 10);
	}

	log_verbose("initialising game finished");
	return 1;
}

/**
 *
 *  rct2: 0x00683499
 */
int rct2_init_directories()
{
	// windows_get_registry_install_info((rct2_install_info*)0x009AA10C, "RollerCoaster Tycoon 2 Setup", "MS Sans Serif", 0);

	// check install directory
	if (!platform_original_game_data_exists(gConfigGeneral.game_path)) {
		log_verbose("install directory does not exist or invalid directory selected, %s", gConfigGeneral.game_path);
		if (!config_find_or_browse_install_directory()) {
			utf8 path[MAX_PATH];
			config_get_default_path(path);
			log_fatal("Invalid RCT2 installation path. Please correct \"game_path\" in %s.", path);
			return 0;
	}
	}

	char separator[] = {platform_get_path_separator(), 0};

	strcpy(RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH, char), gConfigGeneral.game_path);

	strcpy(RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH_SLASH, char), RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH, char));
	strcat(RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH_SLASH, char), separator);

	strcpy(RCT2_ADDRESS(RCT2_ADDRESS_SAVED_GAMES_PATH, char), RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH, char));
	strcat(RCT2_ADDRESS(RCT2_ADDRESS_SAVED_GAMES_PATH, char), separator);
	strcat(RCT2_ADDRESS(RCT2_ADDRESS_SAVED_GAMES_PATH, char), "Saved Games");
	strcat(RCT2_ADDRESS(RCT2_ADDRESS_SAVED_GAMES_PATH, char), separator);

	strcpy(RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH, char));
	strcat(RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), separator);
	strcat(RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), "Scenarios");
	strcat(RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), separator);
	strcat(RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), "*.SC6");

	strcpy(RCT2_ADDRESS(RCT2_ADDRESS_LANDSCAPES_PATH, char), RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH, char));
	strcat(RCT2_ADDRESS(RCT2_ADDRESS_LANDSCAPES_PATH, char), separator);
	strcat(RCT2_ADDRESS(RCT2_ADDRESS_LANDSCAPES_PATH, char), "Landscapes");
	strcat(RCT2_ADDRESS(RCT2_ADDRESS_LANDSCAPES_PATH, char), separator);
	strcat(RCT2_ADDRESS(RCT2_ADDRESS_LANDSCAPES_PATH, char), "*.SC6");

	strcpy(RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH, char));
	strcat(RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), separator);
	strcat(RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), "ObjData");
	strcat(RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), separator);
	strcat(RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), "*.DAT");

	strcpy(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH, char));
	strcat(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), separator);
	strcat(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), "Tracks");
	strcat(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), separator);
	strcat(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), "*.TD?");

	strcpy(RCT2_ADDRESS(RCT2_ADDRESS_SAVED_GAMES_PATH_2, char), RCT2_ADDRESS(RCT2_ADDRESS_SAVED_GAMES_PATH, char));
	return 1;
}

void substitute_path(char *dest, const char *path, const char *filename)
{
	while (*path != '*') {
		*dest++ = *path++;
	}
	strcpy(dest, filename);
}

/**
 *
 *  rct2: 0x00674B42
 */
int rct2_startup_checks()
{
	if (!check_file_paths())
		return 0;

	return 1;
}

void rct2_draw()
{
	if (gIntroState != INTRO_STATE_NONE) {
		return;
	}

	redraw_rain();
	window_update_all();
	gfx_invalidate_pickedup_peep();
	gfx_draw_pickedup_peep();
	update_rain_animation();
	update_palette_effects();

	chat_draw();
	console_draw(&gScreenDPI);

	if (gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) {
		DrawOpenRCT2(0, gScreenHeight - 20);
	}

	if (gConfigGeneral.show_fps) {
		rct2_draw_fps();
	}

	gCurrentDrawCount++;
}

static uint32 _lastFPSUpdateTicks;
static uint32 _lastFPSTicks;
static float _currentFPS;

static float rct2_measure_fps()
{
	uint32 currentTicks = SDL_GetTicks();
	if (currentTicks - _lastFPSUpdateTicks > 500) {
		_lastFPSUpdateTicks = currentTicks;

		uint32 frameDelta = currentTicks - _lastFPSTicks;
		_currentFPS = 1000.0f / frameDelta;
	}
	_lastFPSTicks = currentTicks;
	return _currentFPS;
}

static void rct2_draw_fps()
{
	rct_drawpixelinfo *dpi = &gScreenDPI;
	int x = gScreenWidth / 2;
	int y = 2;

	// Measure FPS
	rct2_measure_fps();

	// Format string
	utf8 buffer[64];
	utf8 *ch = buffer;
	ch = utf8_write_codepoint(ch, FORMAT_MEDIUMFONT);
	ch = utf8_write_codepoint(ch, FORMAT_OUTLINE);
	ch = utf8_write_codepoint(ch, FORMAT_WHITE);

	const char *formatString = (_currentFPS >= 100.0f ? "%.0f" : "%.1f");
	sprintf(ch, formatString, _currentFPS);

	// Draw Text
	int stringWidth = gfx_get_string_width(buffer);
	x = x - (stringWidth / 2);
	gfx_draw_string(dpi, buffer, 0, x, y);

	// Make area dirty so the text doesn't get drawn over the last
	gfx_set_dirty_blocks(x - 16, y - 4, gLastDrawStringX + 16, 16);
}

bool rct2_open_file(const char *path)
{
	char *extension = strrchr(path, '.');
	if (extension == NULL) {
		return false;
	}
	extension++;

	if (_stricmp(extension, "sv6") == 0) {
		strcpy((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2, path);
		game_load_save(path);
		gFirstTimeSave = 0;
		return true;
	} else if (_stricmp(extension, "sc6") == 0) {
		// TODO scenario install
		rct_scenario_basic scenarioBasic;
		strcpy(scenarioBasic.path, path);
		scenario_load_and_play_from_path(scenarioBasic.path);
		return true;
	} else if (_stricmp(extension, "td6") == 0 || _stricmp(extension, "td4") == 0) {
		// TODO track design install
		return true;
	} else if (_stricmp(extension, "sv4") == 0) {
		if (rct1_load_saved_game(path)) {
			game_load_init();
		}
	} else if (_stricmp(extension, "sc4") == 0) {
		if (rct1_load_scenario(path)) {
			scenario_begin();
		}
	}

	return false;
}

/**
 *
 *  rct2: 0x00674C95
 */
int check_file_paths()
{
	for (int pathId = 0; pathId < PATH_ID_END; pathId++) {
		if (!check_file_path(pathId)) {
			return 0;
		}
	}
	return 1;
}

/**
 *
 *  rct2: 0x00674CA5
 */
int check_file_path(int pathId)
{
	const utf8* path = get_file_path(pathId);
	SDL_RWops *file = SDL_RWFromFile(path, "rb");

	switch (pathId) {
	case PATH_ID_G1:
		if (file == NULL) {
			log_fatal("Could not find file %s", path);
			return 0;
		}
		break;

	case PATH_ID_CUSTOM1:
		if (file != NULL) {
			// Store file size in music_custom1_size @ 0x009AF164
			gRideMusicInfoList[36]->length = (uint32)SDL_RWsize(file);
		}
		break;

	case PATH_ID_CUSTOM2:
		if (file != NULL) {
			// Store file size in music_custom2_size @ 0x009AF16E
			gRideMusicInfoList[37]->length = (uint32)SDL_RWsize(file);
		}
		break;
	}

	if (file != NULL) {
		SDL_RWclose(file);
	}

	return 1;
}

void rct2_update()
{
	int tickCount = SDL_GetTicks();
	gTicksSinceLastUpdate = min(tickCount - gLastTickCount, 500);
	gLastTickCount = tickCount;
	if (game_is_not_paused()) {
		gPaletteEffectFrame += gTicksSinceLastUpdate;
	}

	date_update_real_time_of_day();

	// TODO: screenshot countdown process

	network_update();

	// check_cmdline_arg();
	// Screens
	if (gIntroState != INTRO_STATE_NONE) {
		intro_update();
	} else if ((gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) && !gOpenRCT2Headless) {
		title_update();
	} else {
		game_update();
	}

	//stop_completed_sounds(); // removes other sounds that are no longer playing in directsound

	twitch_update();
	chat_update();
	console_update();
}

/**
 *
 *  rct2: 0x00674E6C
 */
const utf8 *get_file_path(int pathId)
{
	static utf8 path[MAX_PATH];
	strcpy(path, gConfigGeneral.game_path);

	// Make sure base path is terminated with a slash
	if (strlen(path) == 0 || path[strlen(path) - 1] != platform_get_path_separator()) {
		if (strlen(path) >= MAX_PATH - 1) {
			log_error("Path for %s too long", RCT2FilePaths[pathId]);
			path[0] = '\0';
			return path;
		}

		char separator[] = {platform_get_path_separator(), 0};
		strcat(path, separator);
	}

	// Concatenate file path
	if (strlen(path) + strlen(RCT2FilePaths[pathId]) > MAX_PATH) {
		log_error("Path for %s too long", RCT2FilePaths[pathId]);
		path[0] = '\0';
		return path;
	}

	char *pathp = path + strnlen(path, sizeof(path));
	strcat(path, RCT2FilePaths[pathId]);
	while (*pathp) {
		if (*pathp == '\\') *pathp = platform_get_path_separator();
		pathp++;
	}

	return path;
}

uint32 get_file_extension_type(const utf8 *path)
{
	const utf8 *extension = path_get_extension(path);
	if (strcicmp(extension, ".dat") == 0) return FILE_EXTENSION_DAT;
	if (strcicmp(extension, ".sc4") == 0) return FILE_EXTENSION_SC4;
	if (strcicmp(extension, ".sv4") == 0) return FILE_EXTENSION_SV4;
	if (strcicmp(extension, ".td4") == 0) return FILE_EXTENSION_TD4;
	if (strcicmp(extension, ".sc6") == 0) return FILE_EXTENSION_SC6;
	if (strcicmp(extension, ".sv6") == 0) return FILE_EXTENSION_SV6;
	if (strcicmp(extension, ".td6") == 0) return FILE_EXTENSION_TD6;
	return FILE_EXTENSION_UNKNOWN;
}
