#include "packer.h"

#include "xxhash/xxhash.c"
#include "fastlz/fastlz.c"

#include "platform/platform.c"
#include "ds.c"
#include "util.c"
#include "allocators.c"
#include "renderer.c"
#include "game.c"

#define FWrite(buf, size, count, file) ((size) * (fwrite(buf, size, count, file)))

#if __linux__
b32 ChangeDir(c8 *dir)
{
	return chdir(dir);
}

u8 **GetFileNamesInDir(Arena *arena, u32 *count)
{
	struct dirent *dir;

	DIR *d = opendir(".");

	*count = 0;
	if (d)
	{
		while ((dir = readdir(d)) != NULL)
		{
			if (!StrEq(dir->d_name, ".") && !StrEq(dir->d_name, ".."))
				*count += 1;
		}
	}

	c8 **file_names = MakeArray(arena, u8*, *count);

	d = opendir(".");
	*count = 0;
	if (d)
	{
		while ((dir = readdir(d)) != NULL)
		{
			if (!StrEq(dir->d_name, ".") && !StrEq(dir->d_name, ".."))
			{
				i32 str_len = StrLen(dir->d_name);
				file_names[*count] = MakeArray(arena, u8, str_len);
				MemCpy(file_names[*count], dir->d_name, str_len);
				*count += 1;
			}
		}
	}

	return (u8 **)file_names;
}

b8 DirVisible(c8 *dir_name)
{
	b8 found = false;

	struct dirent *dir;
	DIR *d = opendir(".");

	if (d)
	{
		while ((dir = readdir(d)) != NULL)
		{
			if (StrEq(dir_name, dir->d_name) && dir->d_type == DT_DIR)
			{
				found = true;
				break;
			}
		}
	}

	return found;
}
#elif _WIN32
# error Not yet implemented
#endif

void SetArrayLookups()
{
	for (i32 i = 0; i < Len(g_Shader_File_Map); i++)
	{
		FileMapping file_mapping = g_Shader_File_Map[i];
		g_Shader_File_Names[file_mapping.ix] = file_mapping.file_name;
	}

	for (int i = 0; i < SHADER_ASSET_MAX; i++)
	{
		Assert(g_Shader_File_Names[i] != NULL, "Spirv shader file name is null");
	}

	for (i32 i = 0; i < Len(g_Texture_File_Map); i++)
	{
		FileMapping file_mapping = g_Texture_File_Map[i];
		g_Texture_File_Names[file_mapping.ix] = file_mapping.file_name;
	}

	for (int i = 0; i < TEXTURE_ASSET_MAX; i++)
	{
		Assert(g_Texture_File_Names[i] != NULL, "Texture file name is null");
	}
}

i32 WriteHeader(FILE *file, FileHeader *header)
{
	i32 offset = 0;
	
	return offset;
}

void MoveToShaderDir(c8 *return_dir)
{
	if (DirVisible("build"))
	{
		Assert(ChangeDir("./build/shaders/glsl") == 0, "Unable to change to shader directory");
		return_dir = "../../..";
	}
	else if (DirVisible("shaders"))
	{
		Assert(ChangeDir("./shaders/glsl") == 0 , "Unable to change to shader directory");
		return_dir = "../..";
	}
	else
		Assert(false, "Unable to find shader directory");
}

void MoveToTextureDir(c8 *return_dir)
{
	if (DirVisible("assets"))
	{
		Assert(ChangeDir("./assets") == 0, "Unable to change to assets directory");
		return_dir = "..";
	}
	if (DirVisible("shaders"))
	{
		Assert(ChangeDir("../assets") == 0, "Unable to change to assets directory");
		return_dir = "../build";
	}
	else 
		Assert(false, "Unable to find assets directory");
}

void InitHeader(FileHeader *header)
{
	Assert(header != NULL, "File header is null");

	header->magic_num = CreateMagicValue('s', 't', 'e', 'g');
	header->version = FILE_VERSION;

	header->asset_counts[SHADER_ASSET] = SHADER_ASSET_MAX;
	header->tag_counts[SHADER_ASSET] = 0;

	header->asset_counts[TEXTURE_ASSET] = TEXTURE_ASSET_MAX;
	header->tag_counts[TEXTURE_ASSET] = TEXTURE_ASSET_MAX;

	header->asset_counts[SOUND_ASSET] = SOUND_ASSET_MAX;
	header->tag_counts[SOUND_ASSET] = SOUND_ASSET_TAG_MAX;

	header->asset_counts[MODEL_ASSET] = MODEL_ASSET_MAX;
	header->tag_counts[MODEL_ASSET] = MODEL_ASSET_TAG_MAX;

	u64 offset = sizeof(FileHeader);

	for (u32 i = 0; i < ASSET_TYPE_MAX; i++)
	{
		if (header->tag_counts[i] > 0)
		{
			header->tag_offsets[i] = offset;
			offset += sizeof(AssetTag) * header->tag_counts[i];
		}
		else
			header->tag_offsets[i] = 0;

		if (header->asset_counts[i] > 0)
		{
			header->asset_offsets[i] = offset;
			offset += sizeof(AssetFile) * header->asset_counts[i];
		}
		else
			header->asset_offsets[i] = 0;
	}
}

void PackFiles(Arena *arena, FileHeader *header)
{
	FILE *file = fopen("assets.sgp", "w+");
	Assert(file != NULL, "File is null");

	Assert(fwrite(header, sizeof(FileHeader), 1, file) == 1, "Unable to write file header");

	u64 data_offset = 0;
	for (u32 i = 0; i < ASSET_TYPE_MAX; i++)
	{
		u64 tag_offset = header->tag_offsets[i] + (header->tag_counts[i] * sizeof(AssetTag));
		if (tag_offset > data_offset)
			data_offset = tag_offset;

		u64 asset_offset = header->asset_offsets[i] + (header->asset_counts[i] * sizeof(AssetFile));
		if (asset_offset > data_offset)
			data_offset = asset_offset;
	}

	c8 *return_dir = "";
	u32 file_count;
	MoveToShaderDir(return_dir);

	AssetFile *shader_assets = MakeArray(arena, AssetFile, SHADER_ASSET_MAX);
	for (u32 i = 0; i < SHADER_ASSET_MAX; i++)
	{
		c8 *asset_name = g_Shader_File_Names[i];

		Printfln("Packing file: %s...", asset_name);

		FILE *asset_file = fopen(asset_name, "r");
		Assert(asset_file != NULL, "Asset file is null");

		int ch = getc(asset_file);
		Assert(ch != EOF, "File begins with EOF");

		while (ch != EOF)
		{
			putc(ch, file);
			ch = getc(asset_file);
		}

		shader_assets[i].data_offset = data_offset;
		shader_assets[i].asset_id = i;

		data_offset = (u64)ftell(file);
	}
}

int main(int argc, c8 **argv)
{
	SetArrayLookups();

	void *mem = MemAllocZeroed(GB(1));
	Arena *arena = CreateArenaDebug(mem, GB(1), __LINE__);

	FILE *file = fopen("assets.sgp", "w+");
	Assert(file != NULL, "File is null");

	FileHeader header = {};
	InitHeader(&header);



	c8 *return_dir;

	c8 **asset_names[ASSET_TYPE_MAX];





	Assert(fseek(file, 0, SEEK_SET) == 0, "error seeking file");
	
	Assert(fclose(file) != EOF, "error closing file");
}
