#include "gosFXHeaders.hpp"

//==========================================================================//
// File:	 gosFX_Effect.cpp												//
// Project:  gosFX					                                        //
// Contents: Base gosFX::Effect Component											//
//--------------------------------------------------------------------------//
// Date      Who    Modification                                            //
// 09/28/98  JTR    Created													//
//																			//
//--------------------------------------------------------------------------//
// Copyright (C) 1997-1998, Virtual World Entertainment, Inc.               //
// All Rights reserved worldwide                                            //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL              //
//==========================================================================//
//

gosFX::EffectLibrary*
	gosFX::EffectLibrary::Instance = NULL;

//------------------------------------------------------------------------------
//
void
	gosFX::EffectLibrary::InitializeClass()
{
	Verify(!Instance);
}

//------------------------------------------------------------------------------
//
void
	gosFX::EffectLibrary::TerminateClass()
{
	if (Instance)
	{
		Check_Object(Instance);
		delete Instance;
		Instance=NULL;
	}
}

//------------------------------------------------------------------------------
//
gosFX::EffectLibrary::EffectLibrary(bool preload)
{
	m_preloadEffects = preload;
}

//------------------------------------------------------------------------------
//
gosFX::EffectLibrary::~EffectLibrary()
{
	#if defined(LAB_ONLY)
		gosFX::Effect__Specification::s_DeleteIsOK = true;
	#endif
	for (unsigned i=0; i<m_effects.GetLength(); ++i)
	{
		if (m_effects[i])
		{
			Check_Object(m_effects[i]);
			delete m_effects[i];
			m_effects[i] = NULL;
			m_effectNames[i] = NULL;
		}
		else
			Verify(!m_effectNames[i]);
	}
	#if defined(LAB_ONLY)
		gosFX::Effect__Specification::s_DeleteIsOK = false;
	#endif
	if (this == Instance)
		Instance = NULL;
}

//------------------------------------------------------------------------------
//
void
	gosFX::EffectLibrary::Load(Stuff::MemoryStream* stream)
{
	gos_PushCurrentHeap(Heap);
	int version = ReadGFXVersion(stream);

	//
	//-------------------------------------------------------------
	// Get the original size and the new size then adjust the total
	//-------------------------------------------------------------
	//
	int orig_len = m_effects.GetLength();
	Verify(orig_len == m_effectNames.GetLength());
	unsigned len;
	*stream >> len;
	m_effects.SetLength(len+orig_len);
	m_effectNames.SetLength(len+orig_len);

	//
	//---------------------------------------------------------------
	// For older versions, the names are stored in the specs directly
	//---------------------------------------------------------------
	//
	int i;
	if (version < 21)
	{
		for (i=0; i<len; ++i)
		{
			m_effects[orig_len+i] = gosFX::Effect::Specification::Create(stream, version);
			Check_Object(m_effects[orig_len+i]);
			m_effects[orig_len+i]->m_effectID = orig_len+i;
			m_effectNames[orig_len+i] = m_effects[orig_len+i]->m_name;
#if defined(LAB_ONLY)
			for (int j=0; j<orig_len; ++j)
			{
				if (!stricmp(m_effectNames[j], m_effectNames[orig_len+i]))
					PAUSE((
						"Warning: effect \"%s\" is duplicated and will be ignored!",
						(const char*)m_effectNames[orig_len+i]
					));
			}
#endif
		}
	}

	//
	//--------------------------------------------------
	// New files have the names at the front of the list
	//--------------------------------------------------
	//
	else
	{
		for (i=0; i<len; ++i)
		{
			*stream >> m_effectNames[orig_len+i];
			m_effectNames[orig_len+i].ToLower();
#if defined(LAB_ONLY)
			stlport::map<Stuff::MString, int>::iterator seeker;
			seeker = m_effectMap.find(m_effectNames[orig_len+i]);
			if (seeker != m_effectMap.end())
			{
				PAUSE((
					"Warning: effect \"%s\" is duplicated!",
					(const char*)m_effectNames[orig_len+i]
					));
			}
#endif
			m_effectMap[m_effectNames[orig_len+i]] = orig_len+i;
		}

		//
		//----------------------------------------------
		// Now actually hook the names up to the effects
		//----------------------------------------------
		//
		for (i=0; i<len; ++i)
		{
			m_effects[orig_len+i] = gosFX::Effect::Specification::Create(stream, version);
			Check_Object(m_effects[orig_len+i]);
			m_effects[orig_len+i]->m_effectID = orig_len+i;
		}
	}
	gos_PopCurrentHeap();
}

//------------------------------------------------------------------------------
//
void
	gosFX::EffectLibrary::Save(Stuff::MemoryStream* stream)
{
	WriteGFXVersion(stream);
	*stream << m_effects.GetLength();
	unsigned i;
	for (i=0; i<m_effects.GetLength(); ++i)
	{
		Check_Object(m_effects[i]);
		*stream << m_effects[i]->m_name;
	}
	for (i=0; i<m_effects.GetLength(); ++i)
	{
		Check_Object(m_effects[i]);
		m_effects[i]->Save(stream);
	}
}

//------------------------------------------------------------------------------
//
void
	gosFX::EffectLibrary::SetLength(unsigned index)
{
	gos_PushCurrentHeap(Heap);
	Verify(index <= m_effects.GetLength());
	#if defined(LAB_ONLY)
		gosFX::Effect__Specification::s_DeleteIsOK = true;
	#endif
	for (unsigned i=index; i<m_effects.GetLength(); ++i)
	{
		if (m_effects[i])
		{
			stlport::map<Stuff::MString, int>::iterator seeker;
			seeker = m_effectMap.find(m_effectNames[i]);
			Verify(seeker != m_effectMap.end());
			m_effectMap.erase(seeker);
			Check_Object(m_effects[i]);
			delete m_effects[i];
			m_effects[i] = NULL;
			m_effectNames[i] = NULL;
		}
		else
			Verify(!m_effectNames[i]);
	}
	#if defined(LAB_ONLY)
		gosFX::Effect__Specification::s_DeleteIsOK = false;
	#endif
	m_effects.SetLength(index);
	m_effectNames.SetLength(index);
	gos_PopCurrentHeap();
}

//------------------------------------------------------------------------------
//
int
	gosFX::EffectLibrary::Find(const char* name)
{
	stlport::map<Stuff::MString, int>::iterator seeker;
	Stuff::MString lwr_name(name);
	lwr_name.ToLower();
	seeker = m_effectMap.find(lwr_name);
	if (seeker != m_effectMap.end())
		return (*seeker).second;
	return -1;
}

//------------------------------------------------------------------------------
//
gosFX::Effect*
	gosFX::EffectLibrary::MakeEffect(
		unsigned index,
		unsigned flags
	)
{
	gosFX::Effect::Specification *spec = m_effects[index];
	Check_Object(spec);
	gosFX::Effect::ClassData *data =
		Cast_Pointer(
			gosFX::Effect::ClassData*, 
			Stuff::RegisteredClass::FindClassData(spec->GetClassID())
		);
	Check_Object(data);
	Check_Pointer(data->effectFactory);
	return (*data->effectFactory)(spec, flags);
}
