/**
* Custom Model
* @version: 8-26-05
* @author Joseph 'Pcjoe' Florencio
*/
#include "hud.h"
#include "cl_util.h"
#include "parsemsg.h"
#include "r_studioint.h"
#include "com_model.h"
#include "custommodel.h"
#include "vgui_teamfortressviewport.h"
#include "fxscript/xmlinterface.h"
extern engine_studio_api_t IEngineStudio;
extern char *sTFClassSelection[];


DECLARE_MESSAGE(m_CustomModel, CustomModel);

int CCustomModelManager::Init(void)
{	HOOK_MESSAGE(CustomModel);
	gHUD.AddHudElem(this);
	Reset();

	for( int i = 0; i < MAX_PLAYERS; i++)
	{	m_CustomList[i] = "";
	}

	m_iFlags |= HUD_ACTIVE;
	return 1;
}

int CCustomModelManager::VidInit( void )
{	BOOL            fFinished;
	HANDLE          hList;
	TCHAR           szSearchDir[MAX_PATH+1];
	WIN32_FIND_DATA FileData;

	// Get directory of custom models
	std::string strCustomDir = gEngfuncs.pfnGetGameDirectory();
	strCustomDir.append("/models/player/custom/");
	// Loop through classes
	for(int i = PC_BUU; i < PC_LASTCLASS; i++)
	{	// get class path
		std::string strClassPath = strCustomDir + sTFClassSelection[i];
		
		// Get the proper directory path
		sprintf(szSearchDir, "%s/*", strClassPath.c_str());

		hList = FindFirstFile(szSearchDir, &FileData);
		// No files found
		if (hList == INVALID_HANDLE_VALUE)
		{	continue;
		}
		else
		{	// Traverse through the directory structure
			fFinished = FALSE;
			while (!fFinished)
			{	// Check the object is a directory or not
				if (FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
				{	if ((strcmp(FileData.cFileName, ".") != 0) && (strcmp(FileData.cFileName, "..") != 0))
					{	// Get xml info path
						std::string strFile = strClassPath + "/";
						strFile.append(FileData.cFileName);
						strFile.append("/info.xml");
						// Load XML
						TiXmlDocument customModelDoc(strFile.c_str());
						if(customModelDoc.LoadFile())
						{	// Parse XML and save
							CCustomModel newCustomModel;
							newCustomModel.setDirectoryName(FileData.cFileName);
							newCustomModel.parseXML(customModelDoc.RootElement(),sTFClassSelection[i]);
							m_CustomModels[i].push_back(newCustomModel);
						}
					}
				}

				if (!FindNextFile(hList, &FileData))
				{	if (GetLastError() == ERROR_NO_MORE_FILES)
					{	fFinished = TRUE;
					}
				}
			}
			FindClose(hList);
		}
	}

	return 1;
}

/**
* Player using Custom Model
*/
bool CCustomModelManager::usingCustomModelPlayer( int iIndex )
{	if(iIndex < 0 || iIndex > MAX_PLAYERS)
	{	return false;
	}
	if(m_CustomList[iIndex] == "")
	{	return false;
	}
	return true;
}

/**
* Get Custom Model for player
*/
model_s *CCustomModelManager::getCustomModelPlayer( int iIndex )
{	if(!usingCustomModelPlayer(iIndex))
	{	return NULL;
	}

	// Get player
	cl_entity_t *pPlayer = gEngfuncs.GetEntityByIndex(iIndex);
	if(!pPlayer ? true : !pPlayer->model)
	{	return NULL;
	}

	int iClass = g_PlayerExtraInfo[iIndex].playerclass;
	for(int i = 0; i < getCustomModelNum(iClass); i++)
	{	// found custom model
		if(m_CustomModels[iClass][i].getDirectoryName() == m_CustomList[iIndex])
		{	return m_CustomModels[iClass][i].getReplacement(pPlayer->model->name);
		}
	}
	return NULL;
}

/**
* Get Custom Model count for class
*/
int CCustomModelManager::getCustomModelNum( int iClass )
{	if((iClass < 0) || (iClass >= CLASS_LASTCLASS))
	{	return 0;
	}
	return m_CustomModels[iClass].size();
}

/**
* Get custom model for class
*/
CCustomModel *CCustomModelManager::getCustomModel( int iClass, int iNum )
{	if((iClass < 0) || (iClass >= CLASS_LASTCLASS))
	{	return NULL;
	}
	if((iNum < 0) || (iNum >= (signed)m_CustomModels[iClass].size()))
	{	return NULL;
	}
	return &m_CustomModels[iClass][iNum];
}

/**
* Get custom model for class
*/
CCustomModel *CCustomModelManager::getCustomModel( int iClass, std::string strModel )
{	int iNum = getCustomModelNum(iClass);
	for(int i = 0; i < iNum; i++)
	{	if(m_CustomModels[iClass][i].getDirectoryName() == strModel)
		{	return &m_CustomModels[iClass][i];
		}
	}
	return NULL;
}

int CCustomModelManager::MsgFunc_CustomModel(const char *pszName,  int iSize, void *pbuf )
{	BEGIN_READ( pbuf, iSize );
	int idx = READ_BYTE();
	std::string strCustomModel = READ_STRING();

	if((idx > 0) && (idx < MAX_PLAYERS))
	{	m_CustomList[idx] = strCustomModel;
	}
	return 1;
}

// Parse XML
void CCustomModel::parseXML( TiXmlElement *pData, std::string strClass )
{	if(!pData)
	{	return;
	}
	
	char *pName = (char*)pData->Attribute("name");
	if(pName)
	{	setName(std::string(pName));
	}

	TiXmlElement* pGroups=NULL;

	// Iterate through groups
	IterateXML(pGroups, pData)
	{	char *pOriginal = (char*)pGroups->Attribute("original");
		char *pReplace = (char*)pGroups->Attribute("replace");
		if(pOriginal && pReplace)
		{	CReplaceMDL replacemdl;
			replacemdl.setOriginalModel(pOriginal);
			replacemdl.setReplaceModel(pReplace);
			char szFull[256];
			// get full model path
			sprintf(szFull,"models/player/custom/%s/%s/%s.mdl",strClass.c_str(),getDirectoryName().c_str(),pReplace);
			int iModelIdx;
			// Precache Model
			gEngfuncs.CL_LoadModel(szFull,&iModelIdx);
			// Get Model
			model_s *pModel = IEngineStudio.Mod_ForName(szFull,0);
			// If valid, set and add to list
			if(pModel)
			{	replacemdl.setModel(pModel);
				m_Models.push_back(replacemdl);
			}
		}
	}
}

// Get Replacement
model_s *CCustomModel::getReplacement( std::string strModel )
{	char szComplete[256];
	char szOriginal[256];
	std::list<CReplaceMDL>::iterator iterFind;
	ForEachIn(iterFind, m_Models)
	{	strcpy(szOriginal,iterFind->getOriginalModel().c_str());
		sprintf(szComplete,"models/player/%s/%s.mdl",szOriginal,szOriginal);
		// Correct model, get replacement
		if(strModel == szComplete)
		{	return iterFind->getModel();
		}
	}
	return NULL;
}

// Constructor
CReplaceMDL::CReplaceMDL( )
{	setModel(NULL);
}