#include "level.h"
#include "baseentity.h"
#include "brush.h"
#include "engine.h"
#include "filesystem.h"
#include "tier1/utlbuffer.h"
#include "tier1/utlstring.h"

struct MapHeader_t
{
	char id[8];
	uint32_t nEntities;
};

struct EntityHeader_t
{
	uint32_t nTriangles;
	uint32_t nProperties;
};

//-----------------------------------------------------------------------------
// Loads level from file, deserializes it and creates entities.
//-----------------------------------------------------------------------------
void ILevel::LoadLevel( const char *szLevelName )
{
	FileHandle_t handle = IFileSystem::Open(CUtlString("%s.fmap",szLevelName), IFILE_READ);
	CUtlBuffer<char> mapdata(IFileSystem::Size(handle));
	IFileSystem::Read(handle, mapdata.GetMemory(), mapdata.GetSize());
	IFileSystem::Close(handle);
	MapHeader_t* pHeader = (MapHeader_t*)mapdata.GetMemory();
	char *pData = (char*)mapdata.GetMemory()+sizeof(MapHeader_t);
	for ( uint32_t i = 0; i < pHeader->nEntities; i++ )
	{

		CUtlBuffer<char> szEntityType(V_strlen(pData)+1);
		V_strcpy(szEntityType, pData);
		pData+=szEntityType.GetSize();
		EntityHeader_t* pEntityHeader = (EntityHeader_t*)pData;
		pData+=sizeof(EntityHeader_t);
		
		CBaseEntity *pEntity = NULL;
		for (auto &entity: g_RegisteredEntities)
		{
			if (!V_strcmp(entity->m_szName, (char*)szEntityType.GetMemory()))
			{
				CBaseEntity *pEnt = entity->m_pfn();
				g_entities.AppendTail(pEnt);
				if (entity->m_pClientfn)
				{
					pEnt->pClientEntity = entity->m_pClientfn();
					pEnt->pClientEntity->pEntity = pEnt;
				}
				pEntity = pEnt;
				break;
			}
		}
		if (!pEntity)
			continue;

		for ( uint32_t j = 0; j<pEntityHeader->nProperties; j++ )
		{	
			CUtlBuffer<char> szParamName(V_strlen(pData)+1);
			V_strcpy(szParamName, pData);
			pData+=szParamName.GetSize();
			CUtlBuffer<char> szParamValue(V_strlen(pData)+1);
			V_strcpy(szParamValue, pData);
			pData+=szParamValue.GetSize();
			pEntity->ReadParameter(szParamName, szParamValue);
		};
		
		CBrushEntity *pBrush = dynamic_cast<CBrushEntity*>(pEntity);
		if (!pBrush)
		{
			pEntity->Spawn();
			if (pEntity->pClientEntity)
				pEntity->pClientEntity->Spawn();
			continue;
		}
		pBrush->m_mesh = CUtlVector<Triangle_t>(0);
		for ( uint32_t j = 0; j<pEntityHeader->nTriangles; j++ )
		{
			Triangle_t triangle = {};
			V_memcpy(triangle.location, pData, 4*9);
			pData+=4*9;
			V_memcpy(triangle.uv, pData, 4*6);
			pData+=4*6;
			CUtlBuffer<char> szTextureName(V_strlen(pData)+1);
			V_strcpy(szTextureName, pData);
			pData+=szTextureName.GetSize();
			pBrush->m_mesh.AppendTail(triangle);
		};
		pBrush->Spawn();
		if (pBrush->pClientEntity)
			pBrush->pClientEntity->Spawn();
	};
};
