/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#define PLFACTORY_PRIVATE
#include "hsTypes.h"
#include "plFactory.h"
#include "hsStream.h"
#include "plCreatable.h"
#include "plCreator.h"
#include "hsUtils.h"
// For class names
#include "plCreatableStrings.h"
static plFactory* theFactory = nil;
plFactory::plFactory()
{
fCreators.SetCountAndZero(plCreatableIndex::plNumClassIndices);
}
plFactory::~plFactory()
{
}
hsBool plFactory::ICreateTheFactory()
{
if( theFactory )
return true;
theFactory = TRACKED_NEW plFactory;
return theFactory != nil;
}
UInt16 plFactory::IGetNumClasses()
{
return plCreatableIndex::plNumClassIndices;
}
void plFactory::IForceShutdown()
{
int i;
for( i = 0; i < fCreators.GetCount(); i++ )
{
if( fCreators[i] )
{
hsRefCnt_SafeUnRef(this);
fCreators[i] = nil;
}
}
}
void plFactory::IShutdown()
{
delete theFactory;
theFactory = nil;
}
UInt16 plFactory::IRegister(UInt16 hClass, plCreator* worker)
{
delete fCreators[hClass];
fCreators[hClass] = worker;
return hClass;
}
//
// return true if creator exists
//
bool plFactory::CanCreate(UInt16 hClass)
{
if( hClass & 0x8000 ) // nil creatable
return false;
if( !theFactory && !ICreateTheFactory() ) // no factory
return false;
if( hClass >= theFactory->IGetNumClasses() ) // invalid index
return false;
return ( theFactory->fCreators[ hClass ] != nil ); // check creator
}
plCreatable* plFactory::ICreate(UInt16 hClass)
{
if (CanCreate(hClass))
{
return fCreators[hClass]->Create();
}
if (!(hClass & 0x8000))
{
hsAssert( false, "Invalid class index or nil creator : plFactory::Create()" );
}
return nil;
}
void plFactory::UnRegister(UInt16 hClass, plCreator* worker)
{
if( theFactory )
{
theFactory->IUnRegister(hClass);
hsRefCnt_SafeUnRef(theFactory);
if( theFactory->RefCnt() < 2 )
IShutdown();
}
}
void plFactory::IUnRegister(UInt16 hClass)
{
fCreators[hClass] = nil;
}
UInt16 plFactory::Register(UInt16 hClass, plCreator* worker)
{
if( !theFactory && !ICreateTheFactory() )
return nil;
hsRefCnt_SafeRef(theFactory);
return theFactory->IRegister(hClass, worker);
}
plCreatable* plFactory::Create(UInt16 hClass)
{
if( !theFactory && !ICreateTheFactory() )
return nil;
return theFactory->ICreate(hClass);
}
UInt16 plFactory::GetNumClasses()
{
if( !theFactory && !ICreateTheFactory() )
return 0;
return theFactory->IGetNumClasses();
}
hsBool plFactory::IDerivesFrom(UInt16 hBase, UInt16 hDer)
{
if( hDer >= fCreators.GetCount() )
return false;
return fCreators[hDer] ? fCreators[hDer]->HasBaseClass(hBase) : false;
}
hsBool plFactory::DerivesFrom(UInt16 hBase, UInt16 hDer)
{
if( !theFactory && !ICreateTheFactory() )
return 0;
return theFactory->IDerivesFrom(hBase, hDer);
}
// slow lookup for things like console
UInt16 plFactory::FindClassIndex(const char* className)
{
int numClasses=GetNumClasses();
if (className && theFactory)
{
int i;
for( i = 0; i < theFactory->fCreators.GetCount(); i++ )
{
if( theFactory->fCreators[i] && !stricmp(className, theFactory->fCreators[i]->ClassName()) )
{
return theFactory->fCreators[i]->ClassIndex();
}
}
}
return numClasses; // err
}
hsBool plFactory::IIsValidClassIndex(UInt16 hClass)
{
return ( hClass < fCreators.GetCount() );
}
hsBool plFactory::IsValidClassIndex(UInt16 hClass)
{
return theFactory->IIsValidClassIndex(hClass);
}
void plFactory::SetTheFactory(plFactory* fac)
{
// There are four cases here.
// 1) Our factory is nil, and we're being given one to use
// Just take it and ref it.
// 2) Our factory is non-nil, and we're being given on to use
// Ours is bogus, pitch it and use the new one.
// 3) Our factory is non-nil, and we're being given a nil one
// Means we're being shut down. Unref the old one. If
// the refcnt drops to one, we're the last one out, so
// go ahead and delete it.
// 4) Our factory is nil and the new one is nil
// Shouldn't happen, but if it does, just ignore it.
if( !theFactory && fac )
{
hsRefCnt_SafeAssign(theFactory, fac);
}
else if( theFactory && fac )
{
theFactory->IForceShutdown();
hsRefCnt_SafeAssign(theFactory, fac);
}
else if( theFactory && !fac )
{
hsRefCnt_SafeUnRef(theFactory);
if( theFactory->RefCnt() < 2 )
delete theFactory;
theFactory = nil;
}
}
plFactory* plFactory::GetTheFactory()
{
if( !theFactory && !ICreateTheFactory() )
return nil;
return theFactory;
}
// For my own nefarious purposes... hsStatusMessage plCreatableIndex
const char *plFactory::GetNameOfClass(UInt16 type)
{
if( type < GetNumClasses() )
{
if( theFactory->fCreators[ type ] )
return theFactory->fCreators[ type ]->ClassName();
static int keyedStringsSize = sizeof(plCreatableStrings::fKeyedStrings)/4;
// If we don't have a creator yet, try falling back on plCreatableStrings
if( type < KEYED_OBJ_DELINEATOR && type= KEYED_OBJ_DELINEATOR && theFactory->fCreators[iter])
{
char Buffer[512];
sprintf(Buffer, "Object %s is a hsKeyedObject, Must appear before 'KEYED_OBJ_DELINEATOR' in plCreatableIndex.h\n",GetNameOfClass(iter));
hsStatusMessage(Buffer);
bogus = true;
}
}
else
{
if(iter < KEYED_OBJ_DELINEATOR && theFactory->fCreators[iter])
{
char Buffer[512];
sprintf(Buffer, "Object %s is NOT a hsKeyedObject, Must appear after 'KEYED_OBJ_DELINEATOR' in plCreatableIndex.h\n",GetNameOfClass(iter));
hsStatusMessage(Buffer);
bogus = true;
}
}
}
hsAssert(!bogus,"The class(s) you just added to plCreatableIndex.h in wrong spot, see output window");
}
void plFactory::Validate(UInt16 keyIndex)
{
theFactory->IValidate(keyIndex);
}
#endif