import aliases;
import std.file;
import std.stdio;
import util;
import std.exception;
import alloc;

version(codegen) 
{
	const u64 ASSET_COUNT = 0;

	enum AssetType { None };
}
else 
{ 
	import assets_codegen;

	const u64 ASSET_COUNT = MODEL_FILES.length + SHADER_FILES.length + TEXTURE_FILES.length;
}

File Asset_File;

FileHeader Asset_Header;

AssetInfo[ASSET_COUNT] Asset_Info;

u8[][ASSET_COUNT] Asset_Data;

const u32 FILE_VERSION = 1;

struct FileHeader
{
	u32 magic;
	u32 file_version;
	u64 asset_count;
	u64 asset_info_offset;
}

struct ModelMeta
{
	u64 index_count;
}

struct TexMeta
{
	u32 w;
	u32 h;
	u32 ch;
}

struct AssetInfo
{
	union
	{
		ModelMeta model;
		TexMeta texture;
	};
	u64 hash;
	u64 offset;
	u64 length;
	AssetType type;
}

bool Asset_Pack_Opened = false;

void
OpenAssetPack()
{
	if (!Asset_Pack_Opened)
	{
		bool success = true;
		string file_path = isFile("build/assets.sgp") ? "build/assets.sgp" : "assets.sgp";

		// TODO: replace this with something that doesn't throw an exception and figure out if this is the best way to handle thing (probably isnt)
		try 
		{
			Asset_File = File(file_path, "rb");
		}
		catch (ErrnoException e)
		{
			Logf("OpenAssetPack failure: Unable to open file %s", file_path);
			assert(false, "Unable to open asset pack file");
		}

		FileHeader[1] header_arr;

		Asset_File.rawRead(header_arr);

		Asset_Header = header_arr[0];

		assert(Asset_Header.file_version == FILE_VERSION, "OpenAssetPack failure: file version incorrect");

		Asset_File.seek(Asset_Header.asset_info_offset);

		Asset_File.rawRead(Asset_Info);
	}
}

u8[]
LoadAssetData(string name)
{
	if (!Asset_Pack_Opened)
	{
		OpenAssetPack();
	}

	u64 hash = Hash(name);
	u8[] data = null;

	foreach(i, info; Asset_Info)
	{
		if (info.hash == hash)
		{
			if (Asset_Data[i].ptr == null)
			{
				Asset_Data[i] = AllocArray!(u8)(info.length);
				Asset_File.seek(info.offset);
				Asset_File.rawRead(Asset_Data[i]);
				assert(Asset_Data[i] != null && Asset_Data[i].length == info.length, "LoadAssetData failure: Asset data loaded incorrectly.");
			}

			data = Asset_Data[i];
			break;
		}
	}

	return data;
}

void
UnloadAssetData(string name)
{
	u64 hash = Hash(name);

	foreach(i, info; Asset_Info)
	{
		if (info.hash == hash)
		{
			if (Asset_Data[i] != null)
			{
				FreeArray(Asset_Data[i]);
				break;
			}
		}
	}
}

