
////////////////////////////////////////////////////////////
//	File:		"AnimationManager.cpp"
//	Author:		[JW] Jason Ware
//	Modified:	[JW] November 17, 2008
//	Purpose:	The manager for all animations in the game.
//				- Singleton
////////////////////////////////////////////////////////////

#include "AnimationManager.h"

#include "CSGD_TextureManager.h"


#include <fstream>
#include <iostream>
using std::ifstream;
using std::ios_base;

/* Data Members */

CAnimationManager CAnimationManager::sm_Instance;

/* Constructors */

CAnimationManager::CAnimationManager()
{

}

/* Accessors */

/* Mutators */

/* Other Functions */

CAnimationManager* CAnimationManager::GetInstance()
{
	return &sm_Instance;
}

/* Destructor */

CAnimationManager::~CAnimationManager()
{
	ShutdownAnimationManager();
}

////////////////////////////////////////////////////////////
//	Function:	GetSpriteSheet
//	Modified:	[JW] November 17, 2008
//	Purpose:	Returns a specified sprite sheet.
////////////////////////////////////////////////////////////
CSprite* CAnimationManager::GetSpriteSheet(const string szSpriteName)
{
	for(unsigned int i = 0; i < m_vSpriteSheets.size(); i++)
		if(m_vSpriteSheets[i]->GetSpriteName() == szSpriteName)
			return m_vSpriteSheets[i];

	return NULL;
}

////////////////////////////////////////////////////////////
//	Function:	LoadAnimations
//	Modified:	[JW] November 17, 2008
//	Purpose:	Loads animations for a given sprite sheet.
////////////////////////////////////////////////////////////
bool CAnimationManager::LoadAnimations(const string szFile)
{
	char errBuffer[100];

	if(szFile.find(".dat", 0) != string::npos)
	{
		ifstream ifs;
		ifs.open(szFile.c_str(), ios_base::in | ios_base::binary);

		if(ifs.is_open())
		{
			CSGD_TextureManager* pTM = CSGD_TextureManager::GetInstance();

			char szSpriteSheet[200];
			char szNumLen[4];
			char *szBuffer;
			int nAnimCount, nFrameCount;
			RECT rRect;
			float fDuration;

			// length of sprite sheet name
			ifs.read(szNumLen, 4);

			// ignore one byte padding in the file
			ifs.ignore();

			// read in the sprite sheet name
			szBuffer = new char[(int)szNumLen[0]+1];
			ifs.read(szBuffer, (int)szNumLen[0]);
			szBuffer[(int)szNumLen[0]] = '\0';

			// create new sprite sheet
			m_vSpriteSheets.push_back(new CSprite(szBuffer));

			// loading the texture into the manager
			sprintf_s(szSpriteSheet, 200, "Resources\\Sprite Sheets\\%s", szBuffer);
			m_vSpriteSheets[m_vSpriteSheets.size()-1]->SetImageID(
				pTM->LoadTexture(szSpriteSheet, D3DCOLOR_ARGB(255, 255, 255, 255))
			);

			// length of animation list
			ifs.read(szNumLen, 4);
			nAnimCount = (int)szNumLen[0];

			for(int i = 0; i < nAnimCount; i++)
			{
				// length of animation name
				ifs.read(szNumLen, 4);
				ifs.ignore();

				// read in the animation 
				delete[] szBuffer;
				szBuffer = new char[(int)szNumLen[0]+1];
				ifs.read(szBuffer, (int)szNumLen[0]);
				szBuffer[(int)szNumLen[0]] = '\0';

				// create new animation
				m_vSpriteSheets[m_vSpriteSheets.size()-1]->AddAnimation(new CAnimation(szBuffer));

				// length of frame list
				ifs.read(szNumLen, 4);
				nFrameCount = (int)szNumLen[0];

				// looping animation or not
				ifs.read(szNumLen, 1);
				m_vSpriteSheets[m_vSpriteSheets.size()-1]->GetAnimation(i)->SetIsLooping(szNumLen[0]);

				for(int j = 0; j < nFrameCount; j++)
				{
					// length of frame name
					ifs.read(szNumLen, 4);
					ifs.ignore();

					// read in the frame name
					delete[] szBuffer;
					szBuffer = new char[(int)szNumLen[0]+1];
					ifs.read(szBuffer, (int)szNumLen[0]);
					szBuffer[(int)szNumLen[0]] = '\0';
					//ifs.ignore();

					// create new frame
					m_vSpriteSheets[m_vSpriteSheets.size()-1]->GetAnimation(i)->AddFrame(new CFrame(szBuffer));

					// obtain the Frame Rect
					rRect = GetRect(ifs);
					m_vSpriteSheets[m_vSpriteSheets.size()-1]->GetAnimation(i)->GetFrame(j)->SetFrameRect(rRect);

					// obtain the Collision Rect
					rRect = GetRect(ifs);
					m_vSpriteSheets[m_vSpriteSheets.size()-1]->GetAnimation(i)->GetFrame(j)->SetCollisionRect(rRect);

					// fill in Anchor Point
					GetAnchor(ifs, i, j);

					// obtain the Frame Duration
					ifs.read((char *)&fDuration, sizeof(float));
					m_vSpriteSheets[m_vSpriteSheets.size()-1]->GetAnimation(i)->GetFrame(j)->SetDuration(fDuration);
				}
			}

			delete[] szBuffer;

			return true;
		}
		else
		{

			sprintf_s(errBuffer, 100, "Unable to open Animation File: %s", szFile.c_str());
		}
	}
	else
	{
		sprintf_s(errBuffer, 100, "Unable to read in Animation File: %s", szFile.c_str());
	}

	return false;
}

////////////////////////////////////////////////////////////
//	Function:	ShutdownAnimationManager
//	Modified:	[JW] November 17, 2008
//	Purpose:	Releases all memory allocated by manager.
////////////////////////////////////////////////////////////
void CAnimationManager::ShutdownAnimationManager(void)
{
	if(!m_vSpriteSheets.empty())
	{
		for(unsigned int i = 0; i < m_vSpriteSheets.size(); i++)
		{
			m_vSpriteSheets[i]->Clear();
			delete m_vSpriteSheets[i];
		}

		m_vSpriteSheets.clear();
	}
}

/* Protected Functions */

/* Private Functions */

////////////////////////////////////////////////////////////
//	Function:	GetAnchor
//	Modified:	[JW] November 17, 2008
//	Purpose:	Helper method to obtain the anchor from 
//					the file.
////////////////////////////////////////////////////////////
void CAnimationManager::GetAnchor(ifstream &ifs, const int nAnimIndex, const int nFrameIndex)
{
	char szNumLen[4];

	// empty the buffer
	szNumLen[0] = szNumLen[1] = szNumLen[2] = szNumLen[3] = 0;
	ifs.ignore();

	// get Anchor X Point
	for(int k = 0; ifs.peek() != ','; k++)
	{
		ifs.read(&szNumLen[k], 1);
	}

	// insert Anchor X Point
	m_vSpriteSheets[m_vSpriteSheets.size()-1]->GetAnimation(nAnimIndex)->GetFrame(nFrameIndex)->SetAnchorX(atoi(szNumLen));

	// empty the buffer
	szNumLen[0] = szNumLen[1] = szNumLen[2] = szNumLen[3] = 0;
	ifs.ignore();

	// get Anchor Y Point
	for(int k = 0; ifs.peek() >= '0' && ifs.peek() <= '9'; k++)
	{
		ifs.read(&szNumLen[k], 1);
	}

	// insert Anchor Y Point
	m_vSpriteSheets[m_vSpriteSheets.size()-1]->GetAnimation(nAnimIndex)->GetFrame(nFrameIndex)->SetAnchorY(atoi(szNumLen));

}

////////////////////////////////////////////////////////////
//	Function:	GetRect
//	Modified:	[JW] November 17, 2008
//	Purpose:	Helper method to obtain the rect from 
//					the file.
////////////////////////////////////////////////////////////
RECT CAnimationManager::GetRect(std::ifstream &ifs)
{
	char szNumLen[4];
	RECT rRect;

	// empty the buffer
	szNumLen[0] = szNumLen[1] = szNumLen[2] = szNumLen[3] = 0;
	ifs.ignore();

	// get Rect X Position
	for(int k = 0; ifs.peek() != ','; k++)
	{
		ifs.read(&szNumLen[k], 1);
	}

	// save Rect X Position
	rRect.left = atoi(szNumLen);

	// empty the buffer
	szNumLen[0] = szNumLen[1] = szNumLen[2] = szNumLen[3] = 0;
	ifs.ignore();

	// get Rect Y Point
	for(int k = 0; ifs.peek() >= '0' && ifs.peek() <= '9'; k++)
	{
		ifs.read(&szNumLen[k], 1);
	}

	// save Rect Y Position
	rRect.top = atoi(szNumLen);

	// empty the buffer
	szNumLen[0] = szNumLen[1] = szNumLen[2] = szNumLen[3] = 0;
	ifs.ignore();

	// get FrameRect Width Position
	for(int k = 0; ifs.peek() != ','; k++)
	{
		ifs.read(&szNumLen[k], 1);
	}

	// save Rect Width Position
	rRect.right = rRect.left + atoi(szNumLen);

	// empty the buffer
	szNumLen[0] = szNumLen[1] = szNumLen[2] = szNumLen[3] = 0;
	ifs.ignore();

	// get Rect Height Point
	for(int k = 0; ifs.peek() >= '0' && ifs.peek() <= '9'; k++)
	{
		ifs.read(&szNumLen[k], 1);
	}

	// save Rect Height Position
	rRect.bottom = rRect.top + atoi(szNumLen);

	return rRect;
}