#include "Visualisation.h"

#include "Sprite.h"
#include "BoxSprite.h"
#include "BallSprite.h"
#include "BackgroundSprite.h"
#include "TextSprite.h"

#include "Colour.h"
#include "DebugUtil.h"

#include "SDL.h"

#include "GameException.h"

template<> Visualisation* TSingleton<Visualisation>::m_pInstance = NULL;

Visualisation::Visualisation()
: m_pScreen(0), m_lastUniqueID(0), m_clearBG(0)
{
	m_transColourKey.r = 0;
	m_transColourKey.g = 255;
	m_transColourKey.b = 0;
}

Visualisation::~Visualisation()
{
}

void Visualisation::Initialise(const int &w, const int &h, const int &bpp)
{
	m_pScreen = SDL_SetVideoMode(w, h, bpp, SDL_SWSURFACE);

	if(!m_pScreen)
	{
		throw GameException(eFatalError, "Visualisation: SDL_SetVideoMode() failed.");
		return;
	}

	SDL_SetCursor(0);
	SDL_ShowCursor(SDL_DISABLE);
	Uint32 key = SDL_MapRGB(m_pScreen->format, m_transColourKey.r, m_transColourKey.g, m_transColourKey.b);
	SDL_SetColorKey(m_pScreen, SDL_SRCCOLORKEY, key);

	m_clearBG = CreateSpriteBox(w, h, ColourRGB(0,0,0), ColourRGB(0,0,0));
}

void Visualisation::Shutdown()
{
	for(size_t i = 0; i < m_vSprites.size(); i++)
	{
		if(m_vSprites[i])
			delete m_vSprites[i];
	}

	m_vSprites.clear();
}

SpriteID Visualisation::CreateSpriteBall(const int &radius, const ColourRGB &centreColour, const ColourRGB &outerColour)
{
	BallSprite* pSprite = new BallSprite(++m_lastUniqueID, radius, centreColour, outerColour);
	m_vSprites.push_back(pSprite);

	return m_lastUniqueID;
}

SpriteID Visualisation::CreateSpriteBox(const unsigned int &w, const unsigned int &h, const ColourRGB &borderColour, const ColourRGB &fillColour, unsigned int borderSize)
{
	BoxSprite* pSprite = new BoxSprite(++m_lastUniqueID, w, h, borderColour, fillColour, borderSize);
	m_vSprites.push_back(pSprite);

	return m_lastUniqueID;
}

SpriteID Visualisation::CreateSpriteFromFile(char *filename)
{
	Sprite* pSprite = new Sprite(++m_lastUniqueID);
	pSprite->InitFromFile(filename);

	m_vSprites.push_back(pSprite);

	return m_lastUniqueID;
}

SpriteID Visualisation::CreateSpriteStarryBackground(const unsigned int &w, const unsigned int &h, const unsigned int &numStars)
{
	BackgroundSprite* pSprite = new BackgroundSprite(++m_lastUniqueID, w, h, numStars);
	DebugUtil::outputDebugText("Visualisation: Background sprite created.\n");
	m_vSprites.push_back(pSprite);

	return m_lastUniqueID;
}

SpriteID Visualisation::CreateSpriteText(const std::string &message, const ColourRGB &colour)
{
	TextSprite* pSprite = new TextSprite(++m_lastUniqueID, message, colour);
	m_vSprites.push_back(pSprite);

	return m_lastUniqueID;
}

void Visualisation::RemoveSprite(const SpriteID &id)
{
	std::vector<Sprite*>::iterator it = m_vSprites.begin();
	while(it != m_vSprites.end())
	{
		if((*it)->GetID() == id)
		{
			(*it)->Shutdown();
			delete (*it);
			it = m_vSprites.erase(it);
		}
		else
			it++;
	}

	throw GameException(eMinorError, "Visualisation: RemoveSprite() failed due to incorrect ID: %d", (int)id);
}

void Visualisation::DrawSprite(SpriteID id, const unsigned int &x, const unsigned int &y, unsigned int frame)
{
	std::vector<Sprite*>::iterator it = m_vSprites.begin();
	while(it != m_vSprites.end())
	{
		if((*it)->GetID() == id)
		{
			(*it)->Draw(x, y, frame);
			return;
		}

		it++;
	}

	throw GameException(eMinorError, "Visualisation: DrawSprite() failed due to incorrect ID: %d", (int)id);
}

void Visualisation::ClearScreen()
{
	DrawSprite(m_clearBG, 0, 0);
}

unsigned int Visualisation::GetSpriteWidth(const SpriteID &id)
{
	std::vector<Sprite*>::iterator it = m_vSprites.begin();
	while(it != m_vSprites.end())
	{
		if((*it)->GetID() == id)
			return (*it)->GetWidth();

		it++;
	}

	throw GameException(eMinorError, "Visualisation: GetSpriteWidth() failed due to incorrect ID: %d", (int)id);
	return 0;
}

unsigned int Visualisation::GetSpriteHeight(const SpriteID &id)
{
	std::vector<Sprite*>::iterator it = m_vSprites.begin();
	while(it != m_vSprites.end())
	{
		if((*it)->GetID() == id)
			return (*it)->GetHeight();

		it++;
	}

	throw GameException(eMinorError, "Visualisation: GetSpriteHeight() failed due to incorrect ID: %d", (int)id);
	return 0;
}
