#include "PlatformPrecomp.h"
#include "FFReader.h"

FFReader::FFReader()
{
	m_fp = NULL;
}

FFReader::~FFReader()
{
	Kill();
}

void FFReader::Kill()
{
	if (m_fp)
	{
		fclose(m_fp);
		m_fp = NULL;
	}

	m_fileHeader.clear();
	m_bUsingBaseDinkFF = false;
	m_error = ERROR_NONE;
}

int FFReader::GetFFRecordIndexFromFileName(const string &fName)
{
	assert(m_fp);

	for (unsigned int i=0; i < m_fileHeader.size(); i++)
	{
		if (strcmp(fName.c_str(), m_fileHeader[i].name) == 0)
			return i;
	}

	return -1;
}

bool FFReader::DoesFileExist( const string &fName )
{

	//LogMsg("Checking for  %s", (m_basePath+fName).c_str());

	if (m_fp)
	{
		if (GetFFRecordIndexFromFileName(fName) != -1) return true;
	}

	if (!m_dmodGamePath.empty())
	{
		if (FileExists(m_dmodGamePath+m_basePath+fName)) return true;
	}
	
	if (!FileExists(m_gamePath+m_basePath+fName))
	{
		//LogMsg("Can't find %s", (m_basePath+fName).c_str());
		return false;
	}
	return true;
}

void FFReader::Init( const string &gamePath, const string &dmodGamePath, const string &basePath, bool bUsingDinkPak )
{

	if (m_basePath == basePath && m_dmodGamePath == dmodGamePath)
	{
		//optimization, detect when we don't have to reload this
		return;
	}

	Kill();

	m_dmodBasePath = basePath;

	if (!bUsingDinkPak)
	{
		m_gamePath = GetBaseAppPath()+gamePath;
		m_basePath = basePath;

	} else
	{
		//using dink.pak
		m_basePath = gamePath+basePath;
		
	}
	
	m_dmodGamePath = dmodGamePath;
	//first scan for an .ff file
	assert(!m_fp);

	

	if (!dmodGamePath.empty())
	{
		m_fp = fopen((m_dmodGamePath+m_dmodBasePath+"dir.ff").c_str(), "rb");
	}
	
	if (!m_fp)
	{
		m_fp = fopen((m_gamePath+m_basePath+"dir.ff").c_str(), "rb");

		if (m_fp)
		{
			m_bUsingBaseDinkFF = true;
		}
	}

	if (!m_fp) return; //no ff to scan in this case

	int totalFiles;
	FFFileInfo f;
	fread(&totalFiles, sizeof(int), 1, m_fp);
	
		for (int i=0; i < totalFiles; i++)
	{
		fread(&f, sizeof(f), 1, m_fp);
		assert(strlen(f.name) < 13);
		ToLowerCase(f.name);
		m_fileHeader.push_back(f);
	}
	
		//LogMsg("FFScanning %s, %d entries", basePath.c_str(), m_fileHeader.size());

}

int FFReader::GetNextFFIndex(int index)
{
	if (m_fileHeader[index+1].offset != 0)
	{
		return index+1;
	}

	assert(index+2 < m_fileHeader.size() );	
	return index+2;
}

void FFReader::SetError(eErrorType error)
{
	m_error = error;
	if (error == ERROR_LOW_MEM)
	{
		GetBaseApp()->SetLastError(BaseApp::ERROR_MEM);
	}
}

byte * FFReader::LoadFFIntoMemory(int index, int *pSizeOut)
{
	int byteSize = m_fileHeader[GetNextFFIndex(index)].offset-m_fileHeader[index].offset;
	if (pSizeOut) *pSizeOut = byteSize;

	fseek(m_fp, m_fileHeader[index].offset, SEEK_SET);


	byte *pMem = new byte[byteSize+1]; //extra one for a null we're going to attach
	
#ifdef _DEBUG
/*
	if (Random(60) == 1)
	{
		//fake a memory error
		SAFE_DELETE_ARRAY(pMem);
		
	}
*/
#endif
	if (!pMem)
	{
		LogError("Out of mem!");
		SetError(ERROR_LOW_MEM);
		return NULL;
	}

	pMem[byteSize] = 0; //ending null, useful if we loaded a text file
	fread(pMem, byteSize, 1, m_fp);
	return pMem;
}


byte * FFReader::LoadFileIntoMemory( string const &fName, int *pSizeOut )
{
	
#ifdef _DEBUG
	//LogMsg("loading for  %s", (m_basePath+fName).c_str());
#endif
	int len;
	byte *pBuff = NULL;

	if (m_fp)
	{
		if (m_bUsingBaseDinkFF && !m_dmodGamePath.empty())
		{
			//you know what?  Let's do a last minute try in the dmod dir as well.

			if (FileExists(m_dmodGamePath+m_dmodBasePath+fName))
			{
				//pBuff = LoadFileIntoMemoryBasic(m_dmodGamePath+m_basePath+fName, &len, false, false);
				pBuff = GetFileManager()->Get(m_dmodGamePath+m_dmodBasePath+fName, &len, false);

				if (!pBuff) SetError(ERROR_LOW_MEM);
				return pBuff;
			}
		}


		int index = GetFFRecordIndexFromFileName(fName);

		if (index != -1)
		{
			//we found it!
			return LoadFFIntoMemory(index, pSizeOut);
		}
	} else
	{
		
		if (!m_dmodGamePath.empty())
		{
		
			if (FileExists(m_dmodGamePath+m_dmodBasePath+fName))
			{
				//pBuff =  LoadFileIntoMemoryBasic(m_dmodGamePath+m_basePath+fName, &len, false, false);
				pBuff = GetFileManager()->Get(m_dmodGamePath+m_dmodBasePath+fName, &len,false);
				if (!pBuff) SetError(ERROR_LOW_MEM);
				return pBuff;

			}
		}
		//pBuff = LoadFileIntoMemoryBasic(m_gamePath+m_basePath+fName, &len, false, false);
		pBuff = GetFileManager()->Get(m_gamePath+m_basePath+fName,&len,  false);
		if (len ==  UINT_MAX) SetError(ERROR_LOW_MEM);
		return pBuff;

	}

	return NULL;
}